Merge "msm: clock-local: Combine _rcg_clk_set_rate() with rcg_clk_set_rate()" into msm-3.0
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 00ff580..fc1d81a 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -295,6 +295,7 @@
CONFIG_MMC_MSM_CARD_HW_DETECTION=y
CONFIG_MMC_MSM_SDC3_SUPPORT=y
CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT=y
+CONFIG_LEDS_GPIO=y
CONFIG_LEDS_MSM_PDM=y
CONFIG_SWITCH=y
CONFIG_SWITCH_GPIO=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index da8b9df..bf4011f 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -291,6 +291,7 @@
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8960=y
CONFIG_THERMAL_PM8XXX=y
+CONFIG_THERMAL_MONITOR=y
CONFIG_MFD_PM8921_CORE=y
CONFIG_MFD_PM8821_CORE=y
CONFIG_MFD_PM8038_CORE=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 10b55dc..6248c98 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -292,6 +292,7 @@
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8960=y
CONFIG_THERMAL_PM8XXX=y
+CONFIG_THERMAL_MONITOR=y
CONFIG_MFD_PM8921_CORE=y
CONFIG_MFD_PM8821_CORE=y
CONFIG_MFD_PM8038_CORE=y
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 0b7e230..69675e1 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -242,7 +242,7 @@
obj-$(CONFIG_ARCH_APQ8064) += devices-8960.o devices-8064.o
board-8960-all-objs += board-8960.o board-8960-camera.o board-8960-display.o board-8960-pmic.o board-8960-storage.o board-8960-gpiomux.o
board-8930-all-objs += board-8930.o board-8930-camera.o board-8930-display.o board-8930-pmic.o board-8930-storage.o board-8930-gpiomux.o devices-8930.o
-board-8064-all-objs += board-8064.o board-8064-pmic.o board-8064-storage.o board-8064-gpiomux.o
+board-8064-all-objs += board-8064.o board-8064-pmic.o board-8064-storage.o board-8064-gpiomux.o board-8064-camera.o
obj-$(CONFIG_MACH_MSM8960_SIM) += board-8960-all.o board-8960-regulator.o
obj-$(CONFIG_MACH_MSM8960_RUMI3) += board-8960-all.o board-8960-regulator.o
obj-$(CONFIG_MACH_MSM8960_CDP) += board-8960-all.o board-8960-regulator.o
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index 9082b07..408f77b 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -68,7 +68,8 @@
#define STBY_KHZ 1
#define HFPLL_NOMINAL_VDD 1050000
-#define HFPLL_LOW_VDD 850000
+#define HFPLL_LOW_VDD_8960 850000
+#define HFPLL_LOW_VDD 945000
#define HFPLL_LOW_VDD_PLL_L_MAX 0x28
#define SECCLKAGD BIT(4)
@@ -200,6 +201,9 @@
.vreg[VREG_DIG] = { "krait0_dig", 1150000,
RPM_VREG_VOTER1,
RPM_VREG_ID_PM8921_S3 },
+ .vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
+ RPM_VREG_VOTER1,
+ RPM_VREG_ID_PM8921_LVS7 },
},
[CPU1] = {
.hfpll_base = MSM_HFPLL_BASE + 0x240,
@@ -212,6 +216,9 @@
.vreg[VREG_DIG] = { "krait0_dig", 1150000,
RPM_VREG_VOTER2,
RPM_VREG_ID_PM8921_S3 },
+ .vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
+ RPM_VREG_VOTER2,
+ RPM_VREG_ID_PM8921_LVS7 },
},
[CPU2] = {
.hfpll_base = MSM_HFPLL_BASE + 0x280,
@@ -224,6 +231,9 @@
.vreg[VREG_DIG] = { "krait0_dig", 1150000,
RPM_VREG_VOTER4,
RPM_VREG_ID_PM8921_S3 },
+ .vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
+ RPM_VREG_VOTER4,
+ RPM_VREG_ID_PM8921_LVS7 },
},
[CPU3] = {
.hfpll_base = MSM_HFPLL_BASE + 0x2C0,
@@ -236,15 +246,20 @@
.vreg[VREG_DIG] = { "krait0_dig", 1150000,
RPM_VREG_VOTER5,
RPM_VREG_ID_PM8921_S3 },
+ .vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
+ RPM_VREG_VOTER5,
+ RPM_VREG_ID_PM8921_LVS7 },
},
[L2] = {
.hfpll_base = MSM_HFPLL_BASE + 0x300,
.aux_clk_sel = MSM_APCS_GCC_BASE + 0x028,
.l2cpmr_iaddr = L2CPMR_IADDR,
+ .vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
+ RPM_VREG_VOTER6,
+ RPM_VREG_ID_PM8921_LVS7 },
},
};
-/*TODO: Update the rpm vreg id when the rpm driver is ready */
static struct scalable scalable_8930[] = {
[CPU0] = {
.hfpll_base = MSM_HFPLL_BASE + 0x200,
@@ -253,16 +268,13 @@
.vreg[VREG_CORE] = { "krait0", 1300000 },
.vreg[VREG_MEM] = { "krait0_mem", 1150000,
RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8921_L24 },
+ RPM_VREG_ID_PM8038_L24 },
.vreg[VREG_DIG] = { "krait0_dig", 1150000,
RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8921_S3 },
- .vreg[VREG_HFPLL_A] = { "hfpll", 2100000,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8921_S8 },
+ RPM_VREG_ID_PM8038_S1 },
.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8921_L23 },
+ RPM_VREG_ID_PM8038_L23 },
},
[CPU1] = {
.hfpll_base = MSM_HFPLL_BASE + 0x300,
@@ -271,27 +283,21 @@
.vreg[VREG_CORE] = { "krait1", 1300000 },
.vreg[VREG_MEM] = { "krait0_mem", 1150000,
RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8921_L24 },
+ RPM_VREG_ID_PM8038_L24 },
.vreg[VREG_DIG] = { "krait0_dig", 1150000,
RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8921_S3 },
- .vreg[VREG_HFPLL_A] = { "hfpll", 2100000,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8921_S8 },
+ RPM_VREG_ID_PM8038_S1 },
.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8921_L23 },
+ RPM_VREG_ID_PM8038_L23 },
},
[L2] = {
.hfpll_base = MSM_HFPLL_BASE + 0x400,
.aux_clk_sel = MSM_APCS_GCC_BASE + 0x028,
.l2cpmr_iaddr = L2CPMR_IADDR,
- .vreg[VREG_HFPLL_A] = { "hfpll", 2100000,
- RPM_VREG_VOTER6,
- RPM_VREG_ID_PM8921_S8 },
.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
RPM_VREG_VOTER6,
- RPM_VREG_ID_PM8921_L23 },
+ RPM_VREG_ID_PM8038_L23 },
},
};
@@ -304,16 +310,13 @@
.vreg[VREG_CORE] = { "krait0", 1300000 },
.vreg[VREG_MEM] = { "krait0_mem", 1150000,
RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8921_L24 },
+ RPM_VREG_ID_PM8038_L24 },
.vreg[VREG_DIG] = { "krait0_dig", 1150000,
RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8921_S3 },
- .vreg[VREG_HFPLL_A] = { "hfpll", 2100000,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8921_S8 },
+ RPM_VREG_ID_PM8038_S1 },
.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8921_L23 },
+ RPM_VREG_ID_PM8038_L23 },
},
[CPU1] = {
.hfpll_base = MSM_HFPLL_BASE + 0x300,
@@ -322,27 +325,21 @@
.vreg[VREG_CORE] = { "krait1", 1300000 },
.vreg[VREG_MEM] = { "krait0_mem", 1150000,
RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8921_L24 },
+ RPM_VREG_ID_PM8038_L24 },
.vreg[VREG_DIG] = { "krait0_dig", 1150000,
RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8921_S3 },
- .vreg[VREG_HFPLL_A] = { "hfpll", 2100000,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8921_S8 },
+ RPM_VREG_ID_PM8038_S1 },
.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8921_L23 },
+ RPM_VREG_ID_PM8038_L23 },
},
[L2] = {
.hfpll_base = MSM_HFPLL_BASE + 0x400,
.aux_clk_sel = MSM_APCS_GCC_BASE + 0x028,
.l2cpmr_iaddr = L2CPMR_IADDR,
- .vreg[VREG_HFPLL_A] = { "hfpll", 2100000,
- RPM_VREG_VOTER6,
- RPM_VREG_ID_PM8921_S8 },
.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
RPM_VREG_VOTER6,
- RPM_VREG_ID_PM8921_L23 },
+ RPM_VREG_ID_PM8038_L23 },
},
};
@@ -741,12 +738,14 @@
{
int rc;
- rc = rpm_vreg_set_voltage(sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
- sc->vreg[VREG_HFPLL_A].rpm_vreg_voter, 2100000,
- sc->vreg[VREG_HFPLL_A].max_vdd, 0);
- if (rc)
- pr_err("%s regulator enable failed (%d)\n",
- sc->vreg[VREG_HFPLL_A].name, rc);
+ if (cpu_is_msm8960()) {
+ rc = rpm_vreg_set_voltage(sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
+ sc->vreg[VREG_HFPLL_A].rpm_vreg_voter, 2100000,
+ sc->vreg[VREG_HFPLL_A].max_vdd, 0);
+ if (rc)
+ pr_err("%s regulator enable failed (%d)\n",
+ sc->vreg[VREG_HFPLL_A].name, rc);
+ }
rc = rpm_vreg_set_voltage(sc->vreg[VREG_HFPLL_B].rpm_vreg_id,
sc->vreg[VREG_HFPLL_B].rpm_vreg_voter, 1800000,
sc->vreg[VREG_HFPLL_B].max_vdd, 0);
@@ -792,12 +791,15 @@
if (rc)
pr_err("%s regulator enable failed (%d)\n",
sc->vreg[VREG_HFPLL_B].name, rc);
- rc = rpm_vreg_set_voltage(sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
- sc->vreg[VREG_HFPLL_A].rpm_vreg_voter, 0,
- 0, 0);
- if (rc)
- pr_err("%s regulator enable failed (%d)\n",
- sc->vreg[VREG_HFPLL_A].name, rc);
+
+ if (cpu_is_msm8960()) {
+ rc = rpm_vreg_set_voltage(sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
+ sc->vreg[VREG_HFPLL_A].rpm_vreg_voter, 0,
+ 0, 0);
+ if (rc)
+ pr_err("%s regulator enable failed (%d)\n",
+ sc->vreg[VREG_HFPLL_A].name, rc);
+ }
}
/* Program the HFPLL rate. Assumes HFPLL is already disabled. */
@@ -1022,9 +1024,12 @@
pll_vdd_dig = 0;
else if (tgt->l2_level->speed.pll_l_val > HFPLL_LOW_VDD_PLL_L_MAX)
pll_vdd_dig = HFPLL_NOMINAL_VDD;
- else
- pll_vdd_dig = HFPLL_LOW_VDD;
-
+ else {
+ if (cpu_is_msm8960())
+ pll_vdd_dig = HFPLL_LOW_VDD_8960;
+ else
+ pll_vdd_dig = HFPLL_LOW_VDD;
+ }
return max(tgt->l2_level->vdd_dig, pll_vdd_dig);
}
@@ -1036,9 +1041,12 @@
pll_vdd_core = 0;
else if (tgt->speed.pll_l_val > HFPLL_LOW_VDD_PLL_L_MAX)
pll_vdd_core = HFPLL_NOMINAL_VDD;
- else
- pll_vdd_core = HFPLL_LOW_VDD;
-
+ else {
+ if (cpu_is_msm8960())
+ pll_vdd_core = HFPLL_LOW_VDD_8960;
+ else
+ pll_vdd_core = HFPLL_LOW_VDD;
+ }
return max(tgt->vdd_core, pll_vdd_core);
}
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
new file mode 100644
index 0000000..f30f0bf
--- /dev/null
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -0,0 +1,375 @@
+/* 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 <linux/i2c.h>
+#include <mach/board.h>
+#include <mach/msm_bus_board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+
+#include "devices.h"
+#include "board-8064.h"
+
+static struct gpiomux_setting cam_settings[] = {
+ {
+ .func = GPIOMUX_FUNC_GPIO, /*suspend*/
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_1, /*active 1*/
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_GPIO, /*active 2*/
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_1, /*active 3*/
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_5, /*active 4*/
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_6, /*active 5*/
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_2, /*active 6*/
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_3, /*active 7*/
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_GPIO, /*i2c suspend*/
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_KEEPER,
+ },
+
+};
+
+
+static struct msm_gpiomux_config apq8064_cam_common_configs[] = {
+ {
+ .gpio = 2,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[2],
+ [GPIOMUX_SUSPENDED] = &cam_settings[0],
+ },
+ },
+ {
+ .gpio = 3,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[1],
+ [GPIOMUX_SUSPENDED] = &cam_settings[0],
+ },
+ },
+ {
+ .gpio = 4,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[1],
+ [GPIOMUX_SUSPENDED] = &cam_settings[0],
+ },
+ },
+ {
+ .gpio = 5,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[1],
+ [GPIOMUX_SUSPENDED] = &cam_settings[0],
+ },
+ },
+ {
+ .gpio = 76,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[2],
+ [GPIOMUX_SUSPENDED] = &cam_settings[0],
+ },
+ },
+ {
+ .gpio = 107,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[2],
+ [GPIOMUX_SUSPENDED] = &cam_settings[0],
+ },
+ },
+};
+
+static struct msm_gpiomux_config apq8064_cam_2d_configs[] = {
+ {
+ .gpio = 10,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &cam_settings[8],
+ },
+ },
+ {
+ .gpio = 11,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &cam_settings[8],
+ },
+ },
+ {
+ .gpio = 12,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &cam_settings[8],
+ },
+ },
+ {
+ .gpio = 13,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &cam_settings[8],
+ },
+ },
+};
+
+#ifdef CONFIG_MSM_CAMERA
+
+static uint16_t msm_cam_gpio_2d_tbl[] = {
+ 5, /*CAMIF_MCLK*/
+ 10, /*CAMIF_I2C_DATA*/
+ 11, /*CAMIF_I2C_CLK*/
+};
+
+static struct msm_camera_gpio_conf gpio_conf = {
+ .cam_gpiomux_conf_tbl = apq8064_cam_2d_configs,
+ .cam_gpiomux_conf_tbl_size = ARRAY_SIZE(apq8064_cam_2d_configs),
+ .cam_gpio_tbl = msm_cam_gpio_2d_tbl,
+ .cam_gpio_tbl_size = ARRAY_SIZE(msm_cam_gpio_2d_tbl),
+};
+
+static struct msm_bus_vectors cam_init_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .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_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors cam_preview_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 27648000,
+ .ib = 110592000,
+ },
+ {
+ .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_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors cam_video_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 140451840,
+ .ib = 561807360,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 206807040,
+ .ib = 488816640,
+ },
+ {
+ .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_EBI_CH0,
+ .ab = 274423680,
+ .ib = 1097694720,
+ },
+ {
+ .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_EBI_CH0,
+ .ab = 540000000,
+ .ib = 1350000000,
+ },
+};
+
+static struct msm_bus_vectors cam_zsl_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 302071680,
+ .ib = 1208286720,
+ },
+ {
+ .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_EBI_CH0,
+ .ab = 540000000,
+ .ib = 1350000000,
+ },
+};
+
+static struct msm_bus_paths cam_bus_client_config[] = {
+ {
+ ARRAY_SIZE(cam_init_vectors),
+ cam_init_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_preview_vectors),
+ cam_preview_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_video_vectors),
+ cam_video_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_snapshot_vectors),
+ cam_snapshot_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_zsl_vectors),
+ cam_zsl_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[] = {
+ {
+ .ioclk.mclk_clk_rate = 24000000,
+ .ioclk.vfe_clk_rate = 228570000,
+ .csid_core = 0,
+ .cam_bus_scale_table = &cam_bus_client_pdata,
+ },
+ {
+ .ioclk.mclk_clk_rate = 24000000,
+ .ioclk.vfe_clk_rate = 228570000,
+ .csid_core = 1,
+ .cam_bus_scale_table = &cam_bus_client_pdata,
+ },
+};
+
+#ifdef CONFIG_IMX074
+static struct msm_camera_sensor_flash_data flash_imx074 = {
+ .flash_type = MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_imx074 = {
+ .mount_angle = 90,
+ .sensor_reset = 107,
+ .sensor_pwd = 85,
+ .vcm_pwd = 0,
+ .vcm_enable = 1,
+};
+
+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,
+ .sensor_platform_info = &sensor_board_info_imx074,
+ .gpio_conf = &gpio_conf,
+ .csi_if = 1,
+ .camera_type = BACK_CAMERA_2D,
+};
+#endif
+
+void __init apq8064_init_cam(void)
+{
+ msm_gpiomux_install(apq8064_cam_common_configs,
+ ARRAY_SIZE(apq8064_cam_common_configs));
+
+ platform_device_register(&msm8960_device_csiphy0);
+ platform_device_register(&msm8960_device_csiphy1);
+ platform_device_register(&msm8960_device_csid0);
+ platform_device_register(&msm8960_device_csid1);
+ platform_device_register(&msm8960_device_ispif);
+ platform_device_register(&msm8960_device_vfe);
+ platform_device_register(&msm8960_device_vpe);
+}
+
+#ifdef CONFIG_I2C
+static struct i2c_board_info apq8064_camera_i2c_boardinfo[] = {
+#ifdef CONFIG_IMX074
+ {
+ I2C_BOARD_INFO("imx074", 0x1A),
+ .platform_data = &msm_camera_sensor_imx074_data,
+ },
+#endif
+};
+
+struct msm_camera_board_info apq8064_camera_board_info = {
+ .board_info = apq8064_camera_i2c_boardinfo,
+ .num_i2c_board_info = ARRAY_SIZE(apq8064_camera_i2c_boardinfo),
+};
+#endif
+#endif
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index ee1c91a..275614b 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -59,6 +59,7 @@
#include "mpm.h"
#include "rpm_resources.h"
#include "pm-boot.h"
+#include "devices-msm8x60.h"
#define MSM_PMEM_ADSP_SIZE 0x7800000
#define MSM_PMEM_AUDIO_SIZE 0x2B4000
@@ -69,7 +70,7 @@
#endif
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-#define MSM_PMEM_KERNEL_EBI1_SIZE 0xB0C000
+#define MSM_PMEM_KERNEL_EBI1_SIZE 0x280000
#define MSM_ION_SF_SIZE MSM_PMEM_SIZE
#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
#define MSM_ION_MM_SIZE MSM_PMEM_ADSP_SIZE
@@ -1068,6 +1069,7 @@
&msm_bus_8064_mm_fabric,
&msm_bus_8064_sys_fpb,
&msm_bus_8064_cpss_fpb,
+ &msm_device_vidc,
};
static struct platform_device *sim_devices[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index 98f453b..1634b05 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-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
@@ -44,4 +44,7 @@
void apq8064_init_mmc(void);
void apq8064_init_gpiomux(void);
void apq8064_init_pmic(void);
+extern struct msm_camera_board_info apq8064_camera_board_info;
+void apq8064_init_cam(void);
+#define APQ_8064_GSBI4_QUP_I2C_BUS_ID 4
#endif
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index 23c94c4..b7400d1 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -26,15 +26,7 @@
#include <mach/ion.h>
#include "devices.h"
-
-/* TODO: Remove this once PM8038 physically becomes
- * available.
- */
-#ifndef MSM8930_PHASE_2
-#include "board-8960.h"
-#else
#include "board-8930.h"
-#endif
#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
#define MSM_FB_PRIM_BUF_SIZE (1376 * 768 * 4 * 3) /* 4 bpp x 3 pages */
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
index 989fde3..c652238 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -110,6 +110,9 @@
REGULATOR_SUPPLY("dsi_vddio", "mipi_dsi.1"),
REGULATOR_SUPPLY("hdmi_avdd", "hdmi_msm.0"),
REGULATOR_SUPPLY("hdmi_vcc", "hdmi_msm.0"),
+ REGULATOR_SUPPLY("pll_vdd", "pil_riva"),
+ REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.1"),
+ REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.2"),
};
VREG_CONSUMERS(L24) = {
REGULATOR_SUPPLY("8038_l24", NULL),
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index eee6d09..dee1e98 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -23,14 +23,7 @@
#include <mach/gpiomux.h>
#include "devices.h"
-/* TODO: Remove this once PM8038 physically becomes
- * available.
- */
-#ifndef MSM8930_PHASE_2
-#include "board-8960.h"
-#else
#include "board-8930.h"
-#endif
/* MSM8960 has 5 SDCC controllers */
enum sdcc_controllers {
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 75d0fb2..69ea6ee 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -126,7 +126,7 @@
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-#define MSM_PMEM_KERNEL_EBI1_SIZE 0xB0C000
+#define MSM_PMEM_KERNEL_EBI1_SIZE 0x280000
#define MSM_ION_SF_SIZE MSM_PMEM_SIZE
#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
#define MSM_ION_MM_SIZE MSM_PMEM_ADSP_SIZE
diff --git a/arch/arm/mach-msm/board-8930.h b/arch/arm/mach-msm/board-8930.h
index 1feb5b8..cefaff5 100644
--- a/arch/arm/mach-msm/board-8930.h
+++ b/arch/arm/mach-msm/board-8930.h
@@ -13,6 +13,8 @@
#ifndef __ARCH_ARM_MACH_MSM_BOARD_MSM8930_H
#define __ARCH_ARM_MACH_MSM_BOARD_MSM8930_H
+#define MSM8930_PHASE_2
+
#include <linux/regulator/gpio-regulator.h>
#include <linux/mfd/pm8xxx/pm8038.h>
#include <linux/i2c.h>
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index f36c3a1..5520bf9 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -110,6 +110,9 @@
REGULATOR_SUPPLY("8921_l23", NULL),
REGULATOR_SUPPLY("dsi_vddio", "mipi_dsi.1"),
REGULATOR_SUPPLY("hdmi_avdd", "hdmi_msm.0"),
+ REGULATOR_SUPPLY("pll_vdd", "pil_riva"),
+ REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.1"),
+ REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.2"),
};
VREG_CONSUMERS(L24) = {
REGULATOR_SUPPLY("8921_l24", NULL),
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index a0a540f..6683f90 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -139,7 +139,7 @@
#define MSM_LIQUID_PMEM_SIZE 0x4000000 /* 64 Mbytes */
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-#define MSM_PMEM_KERNEL_EBI1_SIZE 0xB0C000
+#define MSM_PMEM_KERNEL_EBI1_SIZE 0x280000
#define MSM_ION_SF_SIZE MSM_PMEM_SIZE
#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
#define MSM_ION_MM_SIZE MSM_PMEM_ADSP_SIZE
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index bd570cf..d54ebc5 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -797,6 +797,7 @@
#ifdef CONFIG_MSM_SSBI
static struct msm_ssbi_platform_data msm7x30_ssbi_pm8058_pdata = {
+ .rsl_id = "D:PMIC_SSBI",
.controller_type = MSM_SBI_CTRL_SSBI2,
.slave = {
.name = "pm8058-core",
@@ -2143,10 +2144,10 @@
static struct msm_ts_platform_data msm_ts_data = {
- .min_x = 0,
- .max_x = 4096,
- .min_y = 0,
- .max_y = 4096,
+ .min_x = 284,
+ .max_x = 3801,
+ .min_y = 155,
+ .max_y = 3929,
.min_press = 0,
.max_press = 255,
.inv_x = 4096,
@@ -6348,6 +6349,10 @@
static struct tsc2007_platform_data tsc2007_ts_data = {
.model = 2007,
.x_plate_ohms = 300,
+ .min_x = 210,
+ .max_x = 3832,
+ .min_y = 150,
+ .max_y = 3936,
.irq_flags = IRQF_TRIGGER_LOW,
.init_platform_hw = tsc2007_init,
.exit_platform_hw = tsc2007_exit,
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index a4f1b32..5cb022e 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -2703,9 +2703,10 @@
#define MSM_ION_MM_SIZE 0x3600000 /* (54MB) */
#define MSM_ION_MFC_SIZE SZ_8K
#define MSM_ION_WB_SIZE 0x600000 /* 6MB */
+#define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-#define MSM_ION_HEAP_NUM 7
+#define MSM_ION_HEAP_NUM 8
#else
#define MSM_ION_HEAP_NUM 1
#endif
@@ -5334,6 +5335,14 @@
.memory_type = ION_EBI_TYPE,
.extra_data = (void *) &cp_wb_ion_pdata,
},
+ {
+ .id = ION_AUDIO_HEAP_ID,
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .name = ION_AUDIO_HEAP_NAME,
+ .size = MSM_ION_AUDIO_SIZE,
+ .memory_type = ION_EBI_TYPE,
+ .extra_data = (void *)&co_ion_pdata,
+ },
#endif
}
};
@@ -5382,6 +5391,7 @@
msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MFC_SIZE;
msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_CAMERA_SIZE;
msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_WB_SIZE;
+ msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_AUDIO_SIZE;
#endif
}
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index a21abb8..1f2a5ec 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -793,10 +793,75 @@
__func__, rc);
}
+/* 8625 keypad device information */
+static unsigned int kp_row_gpios_8625[] = {31};
+static unsigned int kp_col_gpios_8625[] = {36, 37};
+
+static const unsigned short keymap_8625[] = {
+ KEY_VOLUMEUP,
+ KEY_VOLUMEDOWN,
+};
+
+static struct gpio_event_matrix_info kp_matrix_info_8625 = {
+ .info.func = gpio_event_matrix_func,
+ .keymap = keymap_8625,
+ .output_gpios = kp_row_gpios_8625,
+ .input_gpios = kp_col_gpios_8625,
+ .noutputs = ARRAY_SIZE(kp_row_gpios_8625),
+ .ninputs = ARRAY_SIZE(kp_col_gpios_8625),
+ .settle_time.tv_nsec = 40 * NSEC_PER_USEC,
+ .poll_time.tv_nsec = 20 * NSEC_PER_MSEC,
+ .flags = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |
+ GPIOKPF_PRINT_UNMAPPED_KEYS,
+};
+
+static struct gpio_event_info *kp_info_8625[] = {
+ &kp_matrix_info_8625.info,
+};
+static struct gpio_event_platform_data kp_pdata_8625 = {
+ .name = "8625_kp",
+ .info = kp_info_8625,
+ .info_count = ARRAY_SIZE(kp_info_8625)
+};
+
+static struct platform_device kp_pdev_8625 = {
+ .name = GPIO_EVENT_DEV_NAME,
+ .id = -1,
+ .dev = {
+ .platform_data = &kp_pdata_8625,
+ },
+};
+
+#define LED_RED_GPIO_8625 49
+#define LED_GREEN_GPIO_8625 34
+
+static struct gpio_led gpio_leds_config_8625[] = {
+ {
+ .name = "green",
+ .gpio = LED_GREEN_GPIO_8625,
+ },
+ {
+ .name = "red",
+ .gpio = LED_RED_GPIO_8625,
+ },
+};
+
+static struct gpio_led_platform_data gpio_leds_pdata_8625 = {
+ .num_leds = ARRAY_SIZE(gpio_leds_config_8625),
+ .leds = gpio_leds_config_8625,
+};
+
+static struct platform_device gpio_leds_8625 = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &gpio_leds_pdata_8625,
+ },
+};
+
static void msm7627a_add_io_devices(void)
{
- if (machine_is_msm7627a_evb())
- return;
+ int rc;
#if defined(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C) || \
defined(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C_MODULE)
@@ -810,6 +875,30 @@
msm_init_pmic_vibrator();
#endif
+ /* keypad */
+ if (machine_is_msm7627a_evb())
+ platform_device_register(&kp_pdev_8625);
+
+ /* leds */
+ if (machine_is_msm7627a_evb()) {
+ rc = gpio_tlmm_config(GPIO_CFG(LED_RED_GPIO_8625, 0,
+ GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
+ GPIO_CFG_16MA), GPIO_CFG_ENABLE);
+ if (rc) {
+ pr_err("%s: gpio_tlmm_config for %d failed\n",
+ __func__, LED_RED_GPIO_8625);
+ }
+
+ rc = gpio_tlmm_config(GPIO_CFG(LED_GREEN_GPIO_8625, 0,
+ GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
+ GPIO_CFG_16MA), GPIO_CFG_ENABLE);
+ if (rc) {
+ pr_err("%s: gpio_tlmm_config for %d failed\n",
+ __func__, LED_GREEN_GPIO_8625);
+ }
+
+ platform_device_register(&gpio_leds_8625);
+ }
}
#define UART1DM_RX_GPIO 45
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 8e8a966..afd3612d 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -363,6 +363,8 @@
};
#define PLL_RATE(l, m, n, v, d, i) { l, m, n, v, (d>>1), i }
+static int rpm_vreg_id_vdd_dig;
+
enum vdd_dig_levels {
VDD_DIG_NONE,
VDD_DIG_LOW,
@@ -378,8 +380,7 @@
[VDD_DIG_NOMINAL] = 1050000,
[VDD_DIG_HIGH] = 1150000
};
-
- return rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S3, RPM_VREG_VOTER3,
+ return rpm_vreg_set_voltage(rpm_vreg_id_vdd_dig, RPM_VREG_VOTER3,
vdd_uv[level], 1150000, 1);
}
@@ -405,28 +406,41 @@
static int set_vdd_l23(struct clk_vdd_class *vdd_class, int level)
{
- int rc;
-
- if (level == VDD_L23_OFF) {
- rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
- RPM_VREG_VOTER3, 0, 0, 1);
- if (rc)
- return rc;
- rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
- RPM_VREG_VOTER3, 0, 0, 1);
- if (rc)
- rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
- RPM_VREG_VOTER3, 1800000, 1800000, 1);
- } else {
- rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
- RPM_VREG_VOTER3, 2200000, 2200000, 1);
- if (rc)
- return rc;
- rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
- RPM_VREG_VOTER3, 1800000, 1800000, 1);
- if (rc)
- rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
- RPM_VREG_VOTER3, 0, 0, 1);
+ int rc = 0;
+ if (cpu_is_msm8960()) {
+ if (level == VDD_L23_OFF) {
+ rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
+ RPM_VREG_VOTER3, 0, 0, 1);
+ if (rc)
+ return rc;
+ rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
+ RPM_VREG_VOTER3, 0, 0, 1);
+ if (rc)
+ rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
+ RPM_VREG_VOTER3, 1800000, 1800000, 1);
+ } else {
+ rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
+ RPM_VREG_VOTER3, 2200000, 2200000, 1);
+ if (rc)
+ return rc;
+ rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
+ RPM_VREG_VOTER3, 1800000, 1800000, 1);
+ if (rc)
+ rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
+ RPM_VREG_VOTER3, 0, 0, 1);
+ }
+ } else if (cpu_is_msm8930() || cpu_is_msm8627()) {
+ if (level == VDD_L23_OFF) {
+ rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8038_L23,
+ RPM_VREG_VOTER3, 0, 0, 1);
+ if (rc)
+ return rc;
+ } else {
+ rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8038_L23,
+ RPM_VREG_VOTER3, 1800000, 1800000, 1);
+ if (rc)
+ return rc;
+ }
}
return rc;
@@ -4799,6 +4813,8 @@
static struct clk_lookup msm_clocks_8064[] = {
CLK_LOOKUP("cxo", cxo_clk.c, NULL),
+ CLK_LOOKUP("cxo", cxo_clk.c, "wcnss_wlan.0"),
+ CLK_LOOKUP("cxo", cxo_clk.c, "pil_riva"),
CLK_LOOKUP("pll2", pll2_clk.c, NULL),
CLK_LOOKUP("pll8", pll8_clk.c, NULL),
CLK_LOOKUP("pll4", pll4_clk.c, NULL),
@@ -5036,6 +5052,8 @@
static struct clk_lookup msm_clocks_8960_v1[] __initdata = {
CLK_LOOKUP("cxo", cxo_clk.c, NULL),
+ CLK_LOOKUP("cxo", cxo_clk.c, "wcnss_wlan.0"),
+ CLK_LOOKUP("cxo", cxo_clk.c, "pil_riva"),
CLK_LOOKUP("pll2", pll2_clk.c, NULL),
CLK_LOOKUP("pll8", pll8_clk.c, NULL),
CLK_LOOKUP("pll4", pll4_clk.c, NULL),
@@ -5641,6 +5659,13 @@
{
size_t num_lookups = ARRAY_SIZE(msm_clocks_8960_v1);
+ if (cpu_is_msm8960() || cpu_is_apq8064())
+ rpm_vreg_id_vdd_dig = RPM_VREG_ID_PM8921_S3;
+ else if (cpu_is_msm8930() || cpu_is_msm8627())
+ rpm_vreg_id_vdd_dig = RPM_VREG_ID_PM8038_S1;
+ else
+ BUG();
+
xo_pxo = msm_xo_get(MSM_XO_PXO, "clock-8960");
if (IS_ERR(xo_pxo)) {
pr_err("%s: msm_xo_get(PXO) failed.\n", __func__);
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index f5d066d..d463c41 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1537,6 +1537,7 @@
};
struct platform_device *msm_footswitch_devices[] = {
+ FS_8X60(FS_MDP, "fs_mdp"),
FS_8X60(FS_ROT, "fs_rot"),
FS_8X60(FS_IJPEG, "fs_ijpeg"),
FS_8X60(FS_VFE, "fs_vfe"),
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index 660884c..631d520 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -49,7 +49,9 @@
#if (NR_CPUS >= 2)
mrc p15, 0, r1, c0, c0, 5 /* MPIDR */
ands r1, r1, #15 /* What CPU am I */
- addne r0, r0, #CPU_SAVED_STATE_SIZE
+ mov r2, #CPU_SAVED_STATE_SIZE
+ mul r1, r1, r2
+ add r0, r0, r1
#endif
stmia r0!, {r4-r14}
@@ -149,15 +151,18 @@
mov r1, #'A'
str r1, [r0, #0x00C]
#endif
- ldr r1, =saved_state_end
+ ldr r1, =saved_state
ldr r2, =msm_pm_collapse_exit
adr r3, msm_pm_collapse_exit
add r1, r1, r3
sub r1, r1, r2
+ add r1, r1, #CPU_SAVED_STATE_SIZE
#if (NR_CPUS >= 2)
mrc p15, 0, r2, c0, c0, 5 /* MPIDR */
ands r2, r2, #15 /* What CPU am I */
- subeq r1, r1, #CPU_SAVED_STATE_SIZE
+ mov r3, #CPU_SAVED_STATE_SIZE
+ mul r2, r2, r3
+ add r1, r1, r2
#endif
#ifdef CONFIG_MSM_CPU_AVS
@@ -268,11 +273,7 @@
.long 0x0
saved_state:
-#if (NR_CPUS >= 2)
- .space CPU_SAVED_STATE_SIZE * 2 /* This code only supports 2 cores */
-#else
- .space CPU_SAVED_STATE_SIZE
-#endif
+ .space CPU_SAVED_STATE_SIZE * NR_CPUS
saved_state_end:
msm_pm_boot_vector:
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index 8961c79..1abfd7b 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -87,6 +87,8 @@
VFE_MSG_V32_START_RECORDING,
VFE_MSG_V32_CAPTURE,
VFE_MSG_OUTPUT_IRQ,
+ VFE_MSG_V2X_PREVIEW,
+ VFE_MSG_V2X_CAPTURE,
};
enum vpe_resp_msg {
diff --git a/arch/arm/mach-msm/pil-q6v4.c b/arch/arm/mach-msm/pil-q6v4.c
index d8ebab5..cdbfc48 100644
--- a/arch/arm/mach-msm/pil-q6v4.c
+++ b/arch/arm/mach-msm/pil-q6v4.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-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
@@ -19,6 +19,7 @@
#include <linux/elf.h>
#include <linux/delay.h>
#include <linux/err.h>
+#include <linux/workqueue.h>
#include <mach/msm_bus.h>
#include <mach/msm_iomap.h>
@@ -68,9 +69,10 @@
void __iomem *modem_base;
unsigned long start_addr;
struct regulator *vreg;
+ struct regulator *pll_supply;
bool vreg_enabled;
struct msm_xo_voter *xo;
- struct timer_list xo_timer;
+ struct delayed_work work;
};
static int pil_q6v4_init_image(struct pil_desc *pil, const u8 *metadata,
@@ -87,27 +89,32 @@
return 0;
}
-static void pil_q6v4_make_xo_proxy_votes(struct device *dev)
+static void pil_q6v4_make_proxy_votes(struct device *dev)
{
struct q6v4_data *drv = dev_get_drvdata(dev);
+ int ret;
msm_xo_mode_vote(drv->xo, MSM_XO_MODE_ON);
- mod_timer(&drv->xo_timer, jiffies+msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
+ if (drv->pll_supply) {
+ ret = regulator_enable(drv->pll_supply);
+ if (ret)
+ dev_err(dev, "failed to enable pll supply\n");
+ }
+ schedule_delayed_work(&drv->work, msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
}
-static void pil_q6v4_remove_xo_proxy_votes(unsigned long data)
+static void pil_q6v4_remove_proxy_votes(struct work_struct *work)
{
- struct q6v4_data *drv = (struct q6v4_data *)data;
-
+ struct q6v4_data *drv = container_of(work, struct q6v4_data, work.work);
+ if (drv->pll_supply)
+ regulator_disable(drv->pll_supply);
msm_xo_mode_vote(drv->xo, MSM_XO_MODE_OFF);
}
-static void pil_q6v4_remove_xo_proxy_votes_now(struct device *dev)
+static void pil_q6v4_remove_proxy_votes_now(struct device *dev)
{
struct q6v4_data *drv = dev_get_drvdata(dev);
-
- if (del_timer(&drv->xo_timer))
- pil_q6v4_remove_xo_proxy_votes((unsigned long)drv);
+ flush_delayed_work(&drv->work);
}
static int pil_q6v4_power_up(struct device *dev)
@@ -184,7 +191,7 @@
const struct q6v4_data *drv = dev_get_drvdata(pil->dev);
const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
- pil_q6v4_make_xo_proxy_votes(pil->dev);
+ pil_q6v4_make_proxy_votes(pil->dev);
err = pil_q6v4_power_up(pil->dev);
if (err)
@@ -300,7 +307,7 @@
drv->vreg_enabled = false;
}
- pil_q6v4_remove_xo_proxy_votes_now(pil->dev);
+ pil_q6v4_remove_proxy_votes_now(pil->dev);
return 0;
}
@@ -324,7 +331,7 @@
const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
int err;
- pil_q6v4_make_xo_proxy_votes(pil->dev);
+ pil_q6v4_make_proxy_votes(pil->dev);
err = pil_q6v4_power_up(pil->dev);
if (err)
@@ -355,7 +362,7 @@
drv->vreg_enabled = false;
}
- pil_q6v4_remove_xo_proxy_votes_now(pil->dev);
+ pil_q6v4_remove_proxy_votes_now(pil->dev);
return ret;
}
@@ -373,6 +380,7 @@
struct q6v4_data *drv;
struct resource *res;
struct pil_desc *desc;
+ int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
@@ -396,9 +404,26 @@
}
desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
- if (!drv)
+ if (!desc)
return -ENOMEM;
+ drv->pll_supply = regulator_get(&pdev->dev, "pll_vdd");
+ if (IS_ERR(drv->pll_supply)) {
+ drv->pll_supply = NULL;
+ } else {
+ ret = regulator_set_voltage(drv->pll_supply, 1800000, 1800000);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to set pll voltage\n");
+ goto err;
+ }
+
+ ret = regulator_set_optimum_mode(drv->pll_supply, 100000);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to set pll optimum mode\n");
+ goto err;
+ }
+ }
+
desc->name = pdata->name;
desc->depends_on = pdata->depends;
desc->dev = &pdev->dev;
@@ -412,26 +437,39 @@
}
drv->vreg = regulator_get(&pdev->dev, "core_vdd");
- if (IS_ERR(drv->vreg))
- return PTR_ERR(drv->vreg);
-
- setup_timer(&drv->xo_timer, pil_q6v4_remove_xo_proxy_votes,
- (unsigned long)drv);
- drv->xo = msm_xo_get(pdata->xo_id, pdata->name);
- if (IS_ERR(drv->xo))
- return PTR_ERR(drv->xo);
-
- if (msm_pil_register(desc)) {
- regulator_put(drv->vreg);
- return -EINVAL;
+ if (IS_ERR(drv->vreg)) {
+ ret = PTR_ERR(drv->vreg);
+ goto err;
}
+
+ drv->xo = msm_xo_get(pdata->xo_id, pdata->name);
+ if (IS_ERR(drv->xo)) {
+ ret = PTR_ERR(drv->xo);
+ goto err_xo;
+ }
+ INIT_DELAYED_WORK(&drv->work, pil_q6v4_remove_proxy_votes);
+
+ ret = msm_pil_register(desc);
+ if (ret)
+ goto err_pil;
return 0;
+err_pil:
+ cancel_delayed_work_sync(&drv->work);
+ msm_xo_put(drv->xo);
+err_xo:
+ regulator_put(drv->vreg);
+err:
+ regulator_put(drv->pll_supply);
+ return ret;
}
static int __devexit pil_q6v4_driver_exit(struct platform_device *pdev)
{
struct q6v4_data *drv = platform_get_drvdata(pdev);
+ cancel_delayed_work_sync(&drv->work);
+ msm_xo_put(drv->xo);
regulator_put(drv->vreg);
+ regulator_put(drv->pll_supply);
return 0;
}
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index 6848c59..7e78a15 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -18,9 +18,11 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/workqueue.h>
+#include <linux/clk.h>
#include <mach/msm_iomap.h>
-#include <mach/msm_xo.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
@@ -80,38 +82,40 @@
struct riva_data {
void __iomem *base;
unsigned long start_addr;
- struct msm_xo_voter *xo;
- struct timer_list xo_timer;
+ struct clk *xo;
+ bool use_cxo;
+ struct delayed_work work;
+ struct regulator *pll_supply;
};
-static void pil_riva_make_xo_proxy_votes(struct device *dev)
+static void pil_riva_make_proxy_votes(struct device *dev)
{
struct riva_data *drv = dev_get_drvdata(dev);
+ int ret;
- msm_xo_mode_vote(drv->xo, MSM_XO_MODE_ON);
- mod_timer(&drv->xo_timer, jiffies+msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
+ if (drv->use_cxo) {
+ ret = clk_prepare_enable(drv->xo);
+ if (ret)
+ dev_err(dev, "failed to enable xo\n");
+ }
+ ret = regulator_enable(drv->pll_supply);
+ if (ret)
+ dev_err(dev, "failed to enable pll supply\n");
+ schedule_delayed_work(&drv->work, msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
}
-static void pil_riva_remove_xo_proxy_votes(unsigned long data)
+static void pil_riva_remove_proxy_votes(struct work_struct *work)
{
- struct riva_data *drv = (struct riva_data *)data;
-
- msm_xo_mode_vote(drv->xo, MSM_XO_MODE_OFF);
+ struct riva_data *drv = container_of(work, struct riva_data, work.work);
+ regulator_disable(drv->pll_supply);
+ if (drv->use_cxo)
+ clk_disable_unprepare(drv->xo);
}
-static void pil_riva_remove_xo_proxy_votes_now(struct device *dev)
+static void pil_riva_remove_proxy_votes_now(struct device *dev)
{
struct riva_data *drv = dev_get_drvdata(dev);
-
- if (del_timer(&drv->xo_timer))
- pil_riva_remove_xo_proxy_votes((unsigned long)drv);
-}
-
-static bool cxo_is_needed(struct riva_data *drv)
-{
- u32 reg = readl_relaxed(drv->base + RIVA_PMU_CFG);
- return (reg & RIVA_PMU_CFG_IRIS_XO_MODE)
- != RIVA_PMU_CFG_IRIS_XO_MODE_48;
+ flush_delayed_work(&drv->work);
}
static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
@@ -128,30 +132,38 @@
return 0;
}
+static bool cxo_is_needed(struct riva_data *drv)
+{
+ u32 reg = readl_relaxed(drv->base + RIVA_PMU_CFG);
+ return (reg & RIVA_PMU_CFG_IRIS_XO_MODE)
+ != RIVA_PMU_CFG_IRIS_XO_MODE_48;
+}
+
static int pil_riva_reset(struct pil_desc *pil)
{
u32 reg, sel;
- bool use_cxo;
struct riva_data *drv = dev_get_drvdata(pil->dev);
void __iomem *base = drv->base;
unsigned long start_addr = drv->start_addr;
+ int ret;
+ ret = clk_prepare_enable(drv->xo);
+ if (ret)
+ return ret;
/* Enable A2XB bridge */
reg = readl_relaxed(base + RIVA_PMU_A2XB_CFG);
reg |= RIVA_PMU_A2XB_CFG_EN;
writel_relaxed(reg, base + RIVA_PMU_A2XB_CFG);
- /* Proxy-vote for CXO if it's needed */
- use_cxo = cxo_is_needed(drv);
- if (use_cxo)
- pil_riva_make_xo_proxy_votes(pil->dev);
+ drv->use_cxo = cxo_is_needed(drv);
+ pil_riva_make_proxy_votes(pil->dev);
/* Program PLL 13 to 960 MHz */
reg = readl_relaxed(RIVA_PLL_MODE);
reg &= ~(PLL_MODE_BYPASSNL | PLL_MODE_OUTCTRL | PLL_MODE_RESET_N);
writel_relaxed(reg, RIVA_PLL_MODE);
- if (use_cxo)
+ if (drv->use_cxo)
writel_relaxed(0x40000C00 | 50, RIVA_PLL_L_VAL);
else
writel_relaxed(0x40000C00 | 40, RIVA_PLL_L_VAL);
@@ -161,7 +173,7 @@
reg = readl_relaxed(RIVA_PLL_MODE);
reg &= ~(PLL_MODE_REF_XO_SEL);
- reg |= use_cxo ? PLL_MODE_REF_XO_SEL_CXO : PLL_MODE_REF_XO_SEL_RF;
+ reg |= drv->use_cxo ? PLL_MODE_REF_XO_SEL_CXO : PLL_MODE_REF_XO_SEL_RF;
writel_relaxed(reg, RIVA_PLL_MODE);
/* Enable PLL 13 */
@@ -226,6 +238,7 @@
/* Take cCPU out of reset */
reg |= RIVA_PMU_OVRD_VAL_CCPU_RESET;
writel_relaxed(reg, base + RIVA_PMU_OVRD_VAL);
+ clk_disable_unprepare(drv->xo);
return 0;
}
@@ -234,7 +247,11 @@
{
struct riva_data *drv = dev_get_drvdata(pil->dev);
u32 reg;
+ int ret;
+ ret = clk_prepare_enable(drv->xo);
+ if (ret)
+ return ret;
/* Put cCPU and cCPU clock into reset */
reg = readl_relaxed(drv->base + RIVA_PMU_OVRD_VAL);
reg &= ~(RIVA_PMU_OVRD_VAL_CCPU_RESET | RIVA_PMU_OVRD_VAL_CCPU_CLK);
@@ -253,7 +270,8 @@
writel_relaxed(0, RIVA_RESET);
mb();
- pil_riva_remove_xo_proxy_votes_now(pil->dev);
+ clk_disable_unprepare(drv->xo);
+ pil_riva_remove_proxy_votes_now(pil->dev);
return 0;
}
@@ -274,19 +292,29 @@
static int pil_riva_reset_trusted(struct pil_desc *pil)
{
struct riva_data *drv = dev_get_drvdata(pil->dev);
+ int ret;
- /* Proxy-vote for CXO if it's needed */
- if (cxo_is_needed(drv))
- pil_riva_make_xo_proxy_votes(pil->dev);
-
- return pas_auth_and_reset(PAS_RIVA);
+ ret = clk_prepare_enable(drv->xo);
+ if (ret)
+ return ret;
+ /* Proxy-vote for resources RIVA needs */
+ pil_riva_make_proxy_votes(pil->dev);
+ ret = pas_auth_and_reset(PAS_RIVA);
+ clk_disable_unprepare(drv->xo);
+ return ret;
}
static int pil_riva_shutdown_trusted(struct pil_desc *pil)
{
- int ret = pas_shutdown(PAS_RIVA);
+ int ret;
+ struct riva_data *drv = dev_get_drvdata(pil->dev);
- pil_riva_remove_xo_proxy_votes_now(pil->dev);
+ ret = clk_prepare_enable(drv->xo);
+ if (ret)
+ return ret;
+ ret = pas_shutdown(PAS_RIVA);
+ pil_riva_remove_proxy_votes_now(pil->dev);
+ clk_disable_unprepare(drv->xo);
return ret;
}
@@ -303,6 +331,7 @@
struct riva_data *drv;
struct resource *res;
struct pil_desc *desc;
+ int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
@@ -321,6 +350,23 @@
if (!desc)
return -ENOMEM;
+ drv->pll_supply = regulator_get(&pdev->dev, "pll_vdd");
+ if (IS_ERR(drv->pll_supply)) {
+ dev_err(&pdev->dev, "failed to get pll supply\n");
+ return PTR_ERR(drv->pll_supply);
+ }
+ ret = regulator_set_voltage(drv->pll_supply, 1800000, 1800000);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to set pll supply voltage\n");
+ goto err;
+ }
+
+ ret = regulator_set_optimum_mode(drv->pll_supply, 100000);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to set pll supply optimum mode\n");
+ goto err;
+ }
+
desc->name = "wcnss";
desc->dev = &pdev->dev;
@@ -332,17 +378,31 @@
dev_info(&pdev->dev, "using non-secure boot\n");
}
- setup_timer(&drv->xo_timer, pil_riva_remove_xo_proxy_votes,
- (unsigned long)drv);
- drv->xo = msm_xo_get(MSM_XO_CXO, desc->name);
- if (IS_ERR(drv->xo))
- return PTR_ERR(drv->xo);
+ drv->xo = clk_get(&pdev->dev, "cxo");
+ if (IS_ERR(drv->xo)) {
+ ret = PTR_ERR(drv->xo);
+ goto err;
+ }
+ INIT_DELAYED_WORK(&drv->work, pil_riva_remove_proxy_votes);
- return msm_pil_register(desc);
+ ret = msm_pil_register(desc);
+ if (ret)
+ goto err_register;
+ return 0;
+err_register:
+ cancel_delayed_work_sync(&drv->work);
+ clk_put(drv->xo);
+err:
+ regulator_put(drv->pll_supply);
+ return ret;
}
static int __devexit pil_riva_remove(struct platform_device *pdev)
{
+ struct riva_data *drv = platform_get_drvdata(pdev);
+ cancel_delayed_work_sync(&drv->work);
+ clk_put(drv->xo);
+ regulator_put(drv->pll_supply);
return 0;
}
diff --git a/arch/arm/mach-msm/qdsp5/adsp_info.c b/arch/arm/mach-msm/qdsp5/adsp_info.c
index 62e385d..dea52bb 100644
--- a/arch/arm/mach-msm/qdsp5/adsp_info.c
+++ b/arch/arm/mach-msm/qdsp5/adsp_info.c
@@ -1,6 +1,6 @@
/* arch/arm/mach-msm/adsp_info.c
*
- * Copyright (c) 2008-2009, 2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-2012 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
@@ -89,7 +89,7 @@
QDSP_MODULE(RMTASK, NULL, 0, NULL, NULL),
#if !defined(CONFIG_ARCH_MSM7X30)
QDSP_MODULE(AUDRECTASK, NULL, 0, NULL, NULL),
- QDSP_MODULE(VFETASK, "vfe_clk", 0, adsp_vfe_verify_cmd,
+ QDSP_MODULE(VFETASK, NULL, 0, adsp_vfe_verify_cmd,
adsp_vfe_patch_event),
QDSP_MODULE(QCAMTASK, NULL, 0, NULL, NULL),
QDSP_MODULE(LPMTASK, NULL, 0, adsp_lpm_verify_cmd, NULL),
diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile
index 908b63d..7b8f3e6 100644
--- a/drivers/gpu/msm/Makefile
+++ b/drivers/gpu/msm/Makefile
@@ -8,7 +8,8 @@
kgsl_pwrscale.o \
kgsl_mmu.o \
kgsl_gpummu.o \
- kgsl_iommu.o
+ kgsl_iommu.o \
+ kgsl_snapshot.o
msm_kgsl_core-$(CONFIG_DEBUG_FS) += kgsl_debugfs.o
msm_kgsl_core-$(CONFIG_MSM_KGSL_CFF_DUMP) += kgsl_cffdump.o
@@ -20,8 +21,10 @@
adreno_ringbuffer.o \
adreno_drawctxt.o \
adreno_postmortem.o \
+ adreno_snapshot.o \
adreno_a2xx.o \
adreno_a2xx_trace.o \
+ adreno_a2xx_snapshot.o \
adreno.o
msm_adreno-$(CONFIG_DEBUG_FS) += adreno_debugfs.o
diff --git a/drivers/gpu/msm/a2xx_reg.h b/drivers/gpu/msm/a2xx_reg.h
index 5ffdea1..50b2745 100644
--- a/drivers/gpu/msm/a2xx_reg.h
+++ b/drivers/gpu/msm/a2xx_reg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -416,4 +416,37 @@
#define REG_A225_GRAS_UCP5W 0x2357
#define REG_A225_GRAS_UCP_ENABLED 0x2360
+/* Debug registers used by snapshot */
+#define REG_PA_SU_DEBUG_CNTL 0x0C80
+#define REG_PA_SU_DEBUG_DATA 0x0C81
+#define REG_RB_DEBUG_CNTL 0x0F26
+#define REG_RB_DEBUG_DATA 0x0F27
+#define REG_PC_DEBUG_CNTL 0x0C38
+#define REG_PC_DEBUG_DATA 0x0C39
+#define REG_GRAS_DEBUG_CNTL 0x0C80
+#define REG_GRAS_DEBUG_DATA 0x0C81
+#define REG_SQ_DEBUG_MISC 0x0D05
+#define REG_SQ_DEBUG_INPUT_FSM 0x0DAE
+#define REG_SQ_DEBUG_CONST_MGR_FSM 0x0DAF
+#define REG_SQ_DEBUG_EXP_ALLOC 0x0DB3
+#define REG_SQ_DEBUG_FSM_ALU_0 0x0DB1
+#define REG_SQ_DEBUG_FSM_ALU_1 0x0DB2
+#define REG_SQ_DEBUG_PTR_BUFF 0x0DB4
+#define REG_SQ_DEBUG_GPR_VTX 0x0DB5
+#define REG_SQ_DEBUG_GPR_PIX 0x0DB6
+#define REG_SQ_DEBUG_TB_STATUS_SEL 0x0DB7
+#define REG_SQ_DEBUG_VTX_TB_0 0x0DB8
+#define REG_SQ_DEBUG_VTX_TB_1 0x0DB9
+#define REG_SQ_DEBUG_VTX_TB_STATE_MEM 0x0DBB
+#define REG_SQ_DEBUG_TP_FSM 0x0DB0
+#define REG_SQ_DEBUG_VTX_TB_STATUS_REG 0x0DBA
+#define REG_SQ_DEBUG_PIX_TB_0 0x0DBC
+#define REG_SQ_DEBUG_PIX_TB_STATUS_REG_0 0x0DBD
+#define REG_SQ_DEBUG_PIX_TB_STATUS_REG_1 0x0DBE
+#define REG_SQ_DEBUG_PIX_TB_STATUS_REG_2 0x0DBF
+#define REG_SQ_DEBUG_PIX_TB_STATUS_REG_3 0x0DC0
+#define REG_SQ_DEBUG_PIX_TB_STATE_MEM 0x0DC1
+#define REG_SQ_DEBUG_MISC_0 0x2309
+#define REG_SQ_DEBUG_MISC_1 0x230A
+
#endif /* __A200_REG_H */
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 03e447b..ce76a8f 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -728,8 +728,21 @@
} else {
kgsl_pwrctrl_set_state(device, KGSL_STATE_DUMP_AND_RECOVER);
INIT_COMPLETION(device->recovery_gate);
- /* Detected a hang - trigger an automatic dump */
+ /* Detected a hang */
+
+
+ /*
+ * Trigger an automatic dump of the state to
+ * the console
+ */
adreno_postmortem_dump(device, 0);
+
+ /*
+ * Make a GPU snapshot. For now, do it after the PM dump so we
+ * can at least be sure the PM dump will work as it always has
+ */
+ kgsl_device_snapshot(device, 1);
+
result = adreno_recover_hang(device);
if (result)
kgsl_pwrctrl_set_state(device, KGSL_STATE_HUNG);
@@ -1094,7 +1107,8 @@
* get an interrupt */
cmds[0] = cp_type3_packet(CP_NOP, 1);
cmds[1] = 0;
- adreno_ringbuffer_issuecmds(device, 0, &cmds[0], 2);
+ adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
+ &cmds[0], 2);
}
mutex_unlock(&device->mutex);
}
@@ -1341,6 +1355,7 @@
.power_stats = adreno_power_stats,
.irqctrl = adreno_irqctrl,
.gpuid = adreno_gpuid,
+ .snapshot = adreno_snapshot,
/* Optional functions */
.setstate = adreno_setstate,
.drawctxt_create = adreno_drawctxt_create,
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index a3d2c00..bdba624 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -24,6 +24,7 @@
KGSL_CONTAINER_OF(device, struct adreno_device, dev)
/* Flags to control command packet settings */
+#define KGSL_CMD_FLAGS_NONE 0x00000000
#define KGSL_CMD_FLAGS_PMODE 0x00000001
#define KGSL_CMD_FLAGS_NO_TS_CMP 0x00000002
#define KGSL_CMD_FLAGS_NOT_KERNEL_CMD 0x00000004
@@ -84,6 +85,7 @@
void (*ctxt_restore)(struct adreno_device *, struct adreno_context *);
irqreturn_t (*irq_handler)(struct adreno_device *);
void (*irq_control)(struct adreno_device *, int);
+ void * (*snapshot)(struct adreno_device *, void *, int *, int);
};
extern struct adreno_gpudev adreno_a2xx_gpudev;
@@ -108,6 +110,9 @@
uint8_t *adreno_convertaddr(struct kgsl_device *device,
unsigned int pt_base, unsigned int gpuaddr, unsigned int size);
+void *adreno_snapshot(struct kgsl_device *device, void *snapshot, int *remain,
+ int hang);
+
static inline int adreno_is_a200(struct adreno_device *adreno_dev)
{
return (adreno_dev->gpurev == ADRENO_REV_A200);
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 16402c3..cf9a60a 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1405,7 +1405,8 @@
"active context flags %08x\n", context->flags);
/* save registers and constants. */
- adreno_ringbuffer_issuecmds(device, 0, context->reg_save, 3);
+ adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
+ context->reg_save, 3);
if (context->flags & CTXT_FLAGS_SHADER_SAVE) {
/* save shader partitioning and instructions. */
@@ -1415,7 +1416,7 @@
/* fixup shader partitioning parameter for
* SET_SHADER_BASES.
*/
- adreno_ringbuffer_issuecmds(device, 0,
+ adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
context->shader_fixup, 3);
context->flags |= CTXT_FLAGS_SHADER_RESTORE;
@@ -1430,7 +1431,7 @@
context->context_gmem_shadow.gmem_save, 3);
/* Restore TP0_CHICKEN */
- adreno_ringbuffer_issuecmds(device, 0,
+ adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
context->chicken_restore, 3);
context->flags |= CTXT_FLAGS_GMEM_RESTORE;
@@ -1481,7 +1482,7 @@
cmds[3] = device->memstore.gpuaddr +
KGSL_DEVICE_MEMSTORE_OFFSET(current_context);
cmds[4] = (unsigned int) context;
- adreno_ringbuffer_issuecmds(device, 0, cmds, 5);
+ adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE, cmds, 5);
kgsl_mmu_setstate(device, context->pagetable);
#ifndef CONFIG_MSM_KGSL_CFF_DUMP_NO_CONTEXT_MEM_DUMP
@@ -1498,26 +1499,27 @@
context->context_gmem_shadow.gmem_restore, 3);
/* Restore TP0_CHICKEN */
- adreno_ringbuffer_issuecmds(device, 0,
+ adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
context->chicken_restore, 3);
context->flags &= ~CTXT_FLAGS_GMEM_RESTORE;
}
/* restore registers and constants. */
- adreno_ringbuffer_issuecmds(device, 0,
+ adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
context->reg_restore, 3);
/* restore shader instructions & partitioning. */
if (context->flags & CTXT_FLAGS_SHADER_RESTORE) {
- adreno_ringbuffer_issuecmds(device, 0,
+ adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
context->shader_restore, 3);
}
if (adreno_is_a20x(adreno_dev)) {
cmds[0] = cp_type3_packet(CP_SET_BIN_BASE_OFFSET, 1);
cmds[1] = context->bin_base_offset;
- adreno_ringbuffer_issuecmds(device, 0, cmds, 2);
+ adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
+ cmds, 2);
}
}
@@ -1704,6 +1706,10 @@
wmb();
}
+/* Defined in adreno_a2xx_snapshot.c */
+void *a2xx_snapshot(struct adreno_device *adreno_dev, void *snapshot,
+ int *remain, int hang);
+
struct adreno_gpudev adreno_a2xx_gpudev = {
.ctxt_gpustate_shadow = a2xx_ctxt_gpustate_shadow,
.ctxt_gmem_shadow = a2xx_ctxt_gmem_shadow,
@@ -1711,4 +1717,5 @@
.ctxt_restore = a2xx_ctxt_restore,
.irq_handler = a2xx_irq_handler,
.irq_control = a2xx_irq_control,
+ .snapshot = a2xx_snapshot,
};
diff --git a/drivers/gpu/msm/adreno_a2xx_snapshot.c b/drivers/gpu/msm/adreno_a2xx_snapshot.c
new file mode 100644
index 0000000..30d692b
--- /dev/null
+++ b/drivers/gpu/msm/adreno_a2xx_snapshot.c
@@ -0,0 +1,356 @@
+/* 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 "kgsl.h"
+#include "adreno.h"
+#include "kgsl_snapshot.h"
+
+#define DEBUG_SECTION_SZ(_dwords) (((_dwords) * sizeof(unsigned int)) \
+ + sizeof(struct kgsl_snapshot_debug))
+
+/* Dump the SX debug registers into a GPU snapshot debug section */
+
+#define SXDEBUG_COUNT 0x1B
+
+static int a2xx_snapshot_sxdebug(struct kgsl_device *device, void *snapshot,
+ int remain, void *priv)
+{
+ struct kgsl_snapshot_debug *header = snapshot;
+ unsigned int *data = snapshot + sizeof(*header);
+ int i;
+
+ if (remain < DEBUG_SECTION_SZ(SXDEBUG_COUNT)) {
+ SNAPSHOT_ERR_NOMEM(device, "SX DEBUG");
+ return 0;
+ }
+
+ header->type = SNAPSHOT_DEBUG_SX;
+ header->size = SXDEBUG_COUNT;
+
+ for (i = 0; i < SXDEBUG_COUNT; i++) {
+ adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1B00 | i);
+ adreno_regread(device, REG_RBBM_DEBUG_OUT, &data[i]);
+ }
+
+ adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
+
+ return DEBUG_SECTION_SZ(SXDEBUG_COUNT);
+}
+
+#define CPDEBUG_COUNT 0x20
+
+static int a2xx_snapshot_cpdebug(struct kgsl_device *device, void *snapshot,
+ int remain, void *priv)
+{
+ struct kgsl_snapshot_debug *header = snapshot;
+ unsigned int *data = snapshot + sizeof(*header);
+ int i;
+
+ if (remain < DEBUG_SECTION_SZ(CPDEBUG_COUNT)) {
+ SNAPSHOT_ERR_NOMEM(device, "CP DEBUG");
+ return 0;
+ }
+
+ header->type = SNAPSHOT_DEBUG_CP;
+ header->size = CPDEBUG_COUNT;
+
+ for (i = 0; i < CPDEBUG_COUNT; i++) {
+ adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1628);
+ adreno_regread(device, REG_RBBM_DEBUG_OUT, &data[i]);
+ }
+
+ adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
+
+ return DEBUG_SECTION_SZ(CPDEBUG_COUNT);
+}
+
+/*
+ * The contents of the SQ debug sections are dword pairs:
+ * [register offset]:[value]
+ * This macro writes both dwords for the given register
+ */
+
+#define SQ_DEBUG_WRITE(_device, _reg, _data, _offset) \
+ do { _data[(_offset)++] = (_reg); \
+ adreno_regread(_device, (_reg), &_data[(_offset)++]); } while (0)
+
+#define SQ_DEBUG_BANK_SIZE 23
+
+static int a2xx_snapshot_sqdebug(struct kgsl_device *device, void *snapshot,
+ int remain, void *priv)
+{
+ struct kgsl_snapshot_debug *header = snapshot;
+ unsigned int *data = snapshot + sizeof(*header);
+ int i, offset = 0;
+ int size = SQ_DEBUG_BANK_SIZE * 2 * 2;
+
+ if (remain < DEBUG_SECTION_SZ(size)) {
+ SNAPSHOT_ERR_NOMEM(device, "SQ Debug");
+ return 0;
+ }
+
+ header->type = SNAPSHOT_DEBUG_SQ;
+ header->size = size;
+
+ for (i = 0; i < 2; i++) {
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_CONST_MGR_FSM+i*0x1000,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_EXP_ALLOC+i*0x1000,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_FSM_ALU_0+i*0x1000,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_FSM_ALU_1+i*0x1000,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_GPR_PIX+i*0x1000,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_GPR_VTX+i*0x1000,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_INPUT_FSM+i*0x1000,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_MISC+i*0x1000,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_MISC_0+i*0x1000,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_MISC_1+i*0x1000,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_0+i*0x1000,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATE_MEM+i*0x1000,
+ data, offset);
+ SQ_DEBUG_WRITE(device,
+ REG_SQ_DEBUG_PIX_TB_STATUS_REG_0+i*0x1000,
+ data, offset);
+ SQ_DEBUG_WRITE(device,
+ REG_SQ_DEBUG_PIX_TB_STATUS_REG_1+i*0x1000,
+ data, offset);
+ SQ_DEBUG_WRITE(device,
+ REG_SQ_DEBUG_PIX_TB_STATUS_REG_2+i*0x1000,
+ data, offset);
+ SQ_DEBUG_WRITE(device,
+ REG_SQ_DEBUG_PIX_TB_STATUS_REG_3+i*0x1000,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PTR_BUFF+i*0x1000,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_TB_STATUS_SEL+i*0x1000,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_TP_FSM+i*0x1000,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_VTX_TB_0+i*0x1000,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_VTX_TB_1+i*0x1000,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_VTX_TB_STATE_MEM+i*0x1000,
+ data, offset);
+ }
+
+ return DEBUG_SECTION_SZ(size);
+}
+
+#define SQ_DEBUG_THREAD_SIZE 7
+
+static int a2xx_snapshot_sqthreaddebug(struct kgsl_device *device,
+ void *snapshot, int remain, void *priv)
+{
+ struct kgsl_snapshot_debug *header = snapshot;
+ unsigned int *data = snapshot + sizeof(*header);
+ int i, offset = 0;
+ int size = SQ_DEBUG_THREAD_SIZE * 2 * 16;
+
+ if (remain < DEBUG_SECTION_SZ(size)) {
+ SNAPSHOT_ERR_NOMEM(device, "SQ THREAD DEBUG");
+ return 0;
+ }
+
+ header->type = SNAPSHOT_DEBUG_SQTHREAD;
+ header->size = size;
+
+ for (i = 0; i < 16; i++) {
+ adreno_regwrite(device, REG_SQ_DEBUG_TB_STATUS_SEL,
+ i | (6<<4) | (i<<7) | (1<<11) | (1<<12)
+ | (i<<16) | (6<<20) | (i<<23));
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_VTX_TB_STATE_MEM,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_VTX_TB_STATUS_REG,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATE_MEM,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATUS_REG_0,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATUS_REG_1,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATUS_REG_2,
+ data, offset);
+ SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATUS_REG_3,
+ data, offset);
+ }
+
+ return DEBUG_SECTION_SZ(size);
+}
+
+#define MIUDEBUG_COUNT 0x10
+
+static int a2xx_snapshot_miudebug(struct kgsl_device *device, void *snapshot,
+ int remain, void *priv)
+{
+ struct kgsl_snapshot_debug *header = snapshot;
+ unsigned int *data = snapshot + sizeof(*header);
+ int i;
+
+ if (remain < DEBUG_SECTION_SZ(MIUDEBUG_COUNT)) {
+ SNAPSHOT_ERR_NOMEM(device, "MIU DEBUG");
+ return 0;
+ }
+
+ header->type = SNAPSHOT_DEBUG_MIU;
+ header->size = MIUDEBUG_COUNT;
+
+ for (i = 0; i < MIUDEBUG_COUNT; i++) {
+ adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1600 | i);
+ adreno_regread(device, REG_RBBM_DEBUG_OUT, &data[i]);
+ }
+
+ adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
+
+ return DEBUG_SECTION_SZ(MIUDEBUG_COUNT);
+}
+
+/* Helper function to snapshot a section of indexed registers */
+
+static void *a2xx_snapshot_indexed_registers(struct kgsl_device *device,
+ void *snapshot, int *remain,
+ unsigned int index, unsigned int data, unsigned int start,
+ unsigned int count)
+{
+ struct kgsl_snapshot_indexed_registers iregs;
+ iregs.index = index;
+ iregs.data = data;
+ iregs.start = start;
+ iregs.count = count;
+
+ return kgsl_snapshot_add_section(device,
+ KGSL_SNAPSHOT_SECTION_INDEXED_REGS, snapshot,
+ remain, kgsl_snapshot_dump_indexed_regs, &iregs);
+}
+
+/* A2XX GPU snapshot function - this is where all of the A2XX specific
+ * bits and pieces are grabbed into the snapshot memory
+ */
+
+void *a2xx_snapshot(struct adreno_device *adreno_dev, void *snapshot,
+ int *remain, int hang)
+{
+ struct kgsl_device *device = &adreno_dev->dev;
+ struct kgsl_snapshot_registers regs;
+ unsigned int pmoverride;
+
+ /* Choose the register set to dump */
+
+ if (adreno_is_a20x(adreno_dev)) {
+ regs.regs = (unsigned int *) a200_registers;
+ regs.count = a200_registers_count;
+ } else {
+ regs.regs = (unsigned int *) a220_registers;
+ regs.count = a220_registers_count;
+ }
+
+ /* Master set of (non debug) registers */
+ snapshot = kgsl_snapshot_add_section(device,
+ KGSL_SNAPSHOT_SECTION_REGS, snapshot, remain,
+ kgsl_snapshot_dump_regs, ®s);
+
+ /* CP_STATE_DEBUG indexed registers */
+ snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+ remain, REG_CP_STATE_DEBUG_INDEX,
+ REG_CP_STATE_DEBUG_DATA, 0x0, 0x14);
+
+ /* CP_ME indexed registers */
+ snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+ remain, REG_CP_ME_CNTL, REG_CP_ME_STATUS,
+ 64, 44);
+
+ /*
+ * Need to temporarily turn off clock gating for the debug bus to
+ * work
+ */
+
+ adreno_regread(device, REG_RBBM_PM_OVERRIDE2, &pmoverride);
+ adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0xFF);
+
+ /* SX debug registers */
+ snapshot = kgsl_snapshot_add_section(device,
+ KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+ a2xx_snapshot_sxdebug, NULL);
+
+ /* SU debug indexed registers (only for < 470) */
+ if (!adreno_is_a22x(adreno_dev))
+ snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+ remain, REG_PA_SU_DEBUG_CNTL,
+ REG_PA_SU_DEBUG_DATA,
+ 0, 0x1B);
+
+ /* CP debug registers */
+ snapshot = kgsl_snapshot_add_section(device,
+ KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+ a2xx_snapshot_cpdebug, NULL);
+
+ /* MH debug indexed registers */
+ snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+ remain, MH_DEBUG_CTRL, MH_DEBUG_DATA, 0x0, 0x40);
+
+ /* Leia only register sets */
+ if (adreno_is_a22x(adreno_dev)) {
+ /* RB DEBUG indexed regisers */
+ snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+ remain, REG_RB_DEBUG_CNTL, REG_RB_DEBUG_DATA, 0, 8);
+
+ /* RB DEBUG indexed registers bank 2 */
+ snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+ remain, REG_RB_DEBUG_CNTL, REG_RB_DEBUG_DATA + 0x1000,
+ 0, 8);
+
+ /* PC_DEBUG indexed registers */
+ snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+ remain, REG_PC_DEBUG_CNTL, REG_PC_DEBUG_DATA, 0, 8);
+
+ /* GRAS_DEBUG indexed registers */
+ snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+ remain, REG_GRAS_DEBUG_CNTL, REG_GRAS_DEBUG_DATA, 0, 4);
+
+ /* MIU debug registers */
+ snapshot = kgsl_snapshot_add_section(device,
+ KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+ a2xx_snapshot_miudebug, NULL);
+
+ /* SQ DEBUG debug registers */
+ snapshot = kgsl_snapshot_add_section(device,
+ KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+ a2xx_snapshot_sqdebug, NULL);
+
+ /*
+ * Reading SQ THREAD causes bad things to happen on a running
+ * system, so only read it if the GPU is already hung
+ */
+
+ if (hang) {
+ /* SQ THREAD debug registers */
+ snapshot = kgsl_snapshot_add_section(device,
+ KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+ a2xx_snapshot_sqthreaddebug, NULL);
+ }
+ }
+
+ /* Reset the clock gating */
+ adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, pmoverride);
+
+ return snapshot;
+}
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
new file mode 100644
index 0000000..fb88a72
--- /dev/null
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -0,0 +1,332 @@
+/* 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 "kgsl.h"
+#include "kgsl_sharedmem.h"
+#include "kgsl_snapshot.h"
+
+#include "adreno.h"
+#include "adreno_pm4types.h"
+#include "a2xx_reg.h"
+
+/* Number of dwords of ringbuffer history to record */
+#define NUM_DWORDS_OF_RINGBUFFER_HISTORY 100
+
+/* Maintain a list of the objects we see during parsing */
+
+#define SNAPSHOT_OBJ_BUFSIZE 64
+
+#define SNAPSHOT_OBJ_TYPE_IB 0
+
+static struct kgsl_snapshot_obj {
+ int type;
+ uint32_t gpuaddr;
+ uint32_t ptbase;
+ void *ptr;
+ int dwords;
+} objbuf[SNAPSHOT_OBJ_BUFSIZE];
+
+/* Pointer to the next open entry in the object list */
+static int objbufptr;
+
+/* Push a new buffer object onto the list */
+static void push_object(struct kgsl_device *device, int type, uint32_t ptbase,
+ uint32_t gpuaddr, int dwords)
+{
+ int index;
+ void *ptr;
+
+ /* Go through the list and see that object has already been seen */
+ for (index = 0; index < objbufptr; index++) {
+ if (objbuf[index].gpuaddr == gpuaddr &&
+ objbuf[index].ptbase == ptbase)
+ return;
+ }
+
+ if (objbufptr == SNAPSHOT_OBJ_BUFSIZE) {
+ KGSL_DRV_ERR(device, "snapshot: too many snapshot objects\n");
+ return;
+ }
+
+ /*
+ * adreno_convertaddr verifies that the IB size is valid - at least in
+ * the context of it being smaller then the allocated memory space
+ */
+ ptr = adreno_convertaddr(device, ptbase, gpuaddr, dwords << 2);
+
+ if (ptr == NULL) {
+ KGSL_DRV_ERR(device,
+ "snapshot: Can't find GPU address for %x\n", gpuaddr);
+ return;
+ }
+
+ /* Put it on the list of things to parse */
+ objbuf[objbufptr].type = type;
+ objbuf[objbufptr].gpuaddr = gpuaddr;
+ objbuf[objbufptr].ptbase = ptbase;
+ objbuf[objbufptr].dwords = dwords;
+ objbuf[objbufptr++].ptr = ptr;
+}
+
+/* Snapshot the istore memory */
+static int snapshot_istore(struct kgsl_device *device, void *snapshot,
+ int remain, void *priv)
+{
+ struct kgsl_snapshot_istore *header = snapshot;
+ unsigned int *data = snapshot + sizeof(*header);
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ int count, i;
+
+ count = adreno_dev->istore_size * ADRENO_ISTORE_WORDS;
+
+ if (remain < (count * 4) + sizeof(*header)) {
+ KGSL_DRV_ERR(device,
+ "snapshot: Not enough memory for the istore section");
+ return 0;
+ }
+
+ header->count = adreno_dev->istore_size;
+
+ for (i = 0; i < count; i++)
+ kgsl_regread(device, ADRENO_ISTORE_START + i, &data[i]);
+
+ return (count * 4) + sizeof(*header);
+}
+
+/* Snapshot the ringbuffer memory */
+static int snapshot_rb(struct kgsl_device *device, void *snapshot,
+ int remain, void *priv)
+{
+ struct kgsl_snapshot_rb *header = snapshot;
+ unsigned int *data = snapshot + sizeof(*header);
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+ unsigned int rbbase, ptbase, rptr, *rbptr;
+ int start, stop, index;
+ int numitems, size;
+
+ /* Get the GPU address of the ringbuffer */
+ kgsl_regread(device, REG_CP_RB_BASE, &rbbase);
+
+ /* Get the physical address of the MMU pagetable */
+ ptbase = kgsl_mmu_get_current_ptbase(device);
+
+ /* Get the current read pointers for the RB */
+ kgsl_regread(device, REG_CP_RB_RPTR, &rptr);
+
+ /* start the dump at the rptr minus some history */
+ start = (int) rptr - NUM_DWORDS_OF_RINGBUFFER_HISTORY;
+ if (start < 0)
+ start += rb->sizedwords;
+
+ /*
+ * Stop the dump at the point where the software last wrote. Don't use
+ * the hardware value here on the chance that it didn't get properly
+ * updated
+ */
+
+ stop = (int) rb->wptr + 16;
+ if (stop > rb->sizedwords)
+ stop -= rb->sizedwords;
+
+ /* Set up the header for the section */
+
+ numitems = (stop > start) ? stop - start :
+ (rb->sizedwords - start) + stop;
+
+ size = (numitems << 2);
+
+ if (remain < size + sizeof(*header)) {
+ KGSL_DRV_ERR(device,
+ "snapshot: Not enough memory for the rb section");
+ return 0;
+ }
+
+ /* Write the sub-header for the section */
+ header->start = start;
+ header->end = stop;
+ header->wptr = rb->wptr;
+ header->rbsize = rb->sizedwords;
+ header->count = numitems;
+
+ index = start;
+ rbptr = rb->buffer_desc.hostptr;
+
+ /*
+ * Loop through the RB, copying the data and looking for indirect
+ * buffers and MMU pagetable changes
+ */
+
+ while (index != rb->wptr) {
+ *data = rbptr[index];
+
+ if (rbptr[index] == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2))
+ push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
+ rbptr[index + 1], rbptr[index + 2]);
+
+ /*
+ * FIXME: Handle upcoming MMU pagetable changes, but only
+ * between the rptr and the wptr
+ */
+
+ index = index + 1;
+
+ if (index == rb->sizedwords)
+ index = 0;
+
+ data++;
+ }
+
+ /* Dump 16 dwords past the wptr, but don't bother interpeting it */
+
+ while (index != stop) {
+ *data = rbptr[index];
+ index = index + 1;
+
+ if (index == rb->sizedwords)
+ index = 0;
+
+ data++;
+ }
+
+ /* Return the size of the section */
+ return size + sizeof(*header);
+}
+
+/* Snapshot the memory for an indirect buffer */
+static int snapshot_ib(struct kgsl_device *device, void *snapshot,
+ int remain, void *priv)
+{
+ struct kgsl_snapshot_ib *header = snapshot;
+ struct kgsl_snapshot_obj *obj = priv;
+ unsigned int *src = obj->ptr;
+ unsigned int *dst = snapshot + sizeof(*header);
+ int i;
+
+ if (remain < (obj->dwords << 2) + sizeof(*header)) {
+ KGSL_DRV_ERR(device,
+ "snapshot: Not enough memory for the ib section");
+ return 0;
+ }
+
+ /* Write the sub-header for the section */
+ header->gpuaddr = obj->gpuaddr;
+ header->ptbase = obj->ptbase;
+ header->size = obj->dwords;
+
+ /* Write the contents of the ib */
+ for (i = 0; i < obj->dwords; i++) {
+ *dst = *src;
+ /* If another IB is discovered, then push it on the list too */
+
+ if (*src == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2)) {
+ push_object(device, SNAPSHOT_OBJ_TYPE_IB, obj->ptbase,
+ *(src + 1), *(src + 2));
+ }
+
+ src++;
+ dst++;
+ }
+
+ return (obj->dwords << 2) + sizeof(*header);
+}
+
+/* Dump another item on the current pending list */
+static void *dump_object(struct kgsl_device *device, int obj, void *snapshot,
+ int *remain)
+{
+ switch (objbuf[obj].type) {
+ case SNAPSHOT_OBJ_TYPE_IB:
+ snapshot = kgsl_snapshot_add_section(device,
+ KGSL_SNAPSHOT_SECTION_IB, snapshot, remain,
+ snapshot_ib, &objbuf[obj]);
+ break;
+ default:
+ KGSL_DRV_ERR(device,
+ "snapshot: Invalid snapshot object type: %d\n",
+ objbuf[obj].type);
+ break;
+ }
+
+ return snapshot;
+}
+
+/* adreno_snapshot - Snapshot the Adreno GPU state
+ * @device - KGSL device to snapshot
+ * @snapshot - Pointer to the start of memory to write into
+ * @remain - A pointer to how many bytes of memory are remaining in the snapshot
+ * @hang - set if this snapshot was automatically triggered by a GPU hang
+ * This is a hook function called by kgsl_snapshot to snapshot the
+ * Adreno specific information for the GPU snapshot. In turn, this function
+ * calls the GPU specific snapshot function to get core specific information.
+ */
+
+void *adreno_snapshot(struct kgsl_device *device, void *snapshot, int *remain,
+ int hang)
+{
+ int i;
+ uint32_t ptbase, ibbase, ibsize;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+ /* Reset the list of objects */
+ objbufptr = 0;
+
+ /* Get the physical address of the MMU pagetable */
+ ptbase = kgsl_mmu_get_current_ptbase(device);
+
+ /* Dump the ringbuffer */
+ snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_RB,
+ snapshot, remain, snapshot_rb, NULL);
+
+ /*
+ * Make sure that the IBs described in the CP registers are on the
+ * list of objects
+ */
+ kgsl_regread(device, REG_CP_IB1_BASE, &ibbase);
+ kgsl_regread(device, REG_CP_IB1_BUFSZ, &ibsize);
+
+ if (ibsize)
+ push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
+ ibbase, ibsize);
+
+ kgsl_regread(device, REG_CP_IB2_BASE, &ibbase);
+ kgsl_regread(device, REG_CP_IB2_BUFSZ, &ibsize);
+
+ if (ibsize)
+ push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
+ ibbase, ibsize);
+
+ /*
+ * Go through the list of found objects and dump each one. As the IBs
+ * are parsed, more objects might be found, and objbufptr will increase
+ */
+ for (i = 0; i < objbufptr; i++)
+ snapshot = dump_object(device, i, snapshot, remain);
+
+ /*
+ * Only dump the istore on a hang - reading it on a running system
+ * has a non 0 chance of hanging the GPU
+ */
+
+ if (hang) {
+ snapshot = kgsl_snapshot_add_section(device,
+ KGSL_SNAPSHOT_SECTION_ISTORE, snapshot, remain,
+ snapshot_istore, NULL);
+ }
+
+ /* Add GPU specific sections - registers mainly, but other stuff too */
+ if (adreno_dev->gpudev->snapshot)
+ snapshot = adreno_dev->gpudev->snapshot(adreno_dev, snapshot,
+ remain, hang);
+
+ return snapshot;
+}
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index c6e78dd..1b6696b 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2097,6 +2097,8 @@
if (minor == KGSL_DEVICE_MAX)
return;
+ kgsl_device_snapshot_close(device);
+
kgsl_cffdump_close(device->id);
kgsl_pwrctrl_uninit_sysfs(device);
@@ -2199,6 +2201,9 @@
idr_init(&device->context_idr);
+ /* Initalize the snapshot engine */
+ kgsl_device_snapshot_init(device);
+
/* sysfs and debugfs initalization - failure here is non fatal */
/* Initialize logging */
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index f82b038..8ea5279 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -90,6 +90,8 @@
struct kgsl_power_stats *stats);
void (*irqctrl)(struct kgsl_device *device, int state);
unsigned int (*gpuid)(struct kgsl_device *device);
+ void * (*snapshot)(struct kgsl_device *device, void *snapshot,
+ int *remain, int hang);
/* Optional functions - these functions are not mandatory. The
driver will check that the function pointer is not NULL before
calling the hook */
@@ -164,6 +166,15 @@
struct idr context_idr;
struct early_suspend display_off;
+ void *snapshot; /* Pointer to the snapshot memory region */
+ int snapshot_maxsize; /* Max size of the snapshot region */
+ int snapshot_size; /* Current size of the snapshot region */
+ u32 snapshot_timestamp; /* Timestamp of the last valid snapshot */
+ int snapshot_frozen; /* 1 if the snapshot output is frozen until
+ it gets read by the user. This avoids
+ losing the output on multiple hangs */
+ struct kobject snapshot_kobj;
+
/* Logging levels */
int cmd_log;
int ctxt_log;
@@ -320,4 +331,8 @@
const char *kgsl_pwrstate_to_str(unsigned int state);
+int kgsl_device_snapshot_init(struct kgsl_device *device);
+int kgsl_device_snapshot(struct kgsl_device *device, int hang);
+void kgsl_device_snapshot_close(struct kgsl_device *device);
+
#endif /* __KGSL_DEVICE_H */
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
new file mode 100644
index 0000000..72df148b
--- /dev/null
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -0,0 +1,484 @@
+/* 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/vmalloc.h>
+#include <linux/time.h>
+#include <linux/sysfs.h>
+#include <linux/utsname.h>
+#include <linux/sched.h>
+#include <linux/idr.h>
+
+#include "kgsl.h"
+#include "kgsl_log.h"
+#include "kgsl_device.h"
+#include "kgsl_sharedmem.h"
+#include "kgsl_snapshot.h"
+
+/* idr_for_each function to count the number of contexts */
+
+static int snapshot_context_count(int id, void *ptr, void *data)
+{
+ int *count = data;
+ *count = *count + 1;
+
+ return 0;
+}
+
+/*
+ * To simplify the iterator loop use a global pointer instead of trying
+ * to pass around double star references to the snapshot data
+ */
+
+static void *_ctxtptr;
+
+static int snapshot_context_info(int id, void *ptr, void *data)
+{
+ struct kgsl_snapshot_linux_context *header = _ctxtptr;
+ struct kgsl_context *context = ptr;
+ struct kgsl_device *device = context->dev_priv->device;
+
+ header->id = id;
+
+ /* Future-proof for per-context timestamps - for now, just
+ * return the global timestamp for all contexts
+ */
+
+ header->timestamp_queued = -1;
+ header->timestamp_retired = device->ftbl->readtimestamp(device,
+ KGSL_TIMESTAMP_RETIRED);
+
+ _ctxtptr += sizeof(struct kgsl_snapshot_linux_context);
+
+ return 0;
+}
+
+/* Snapshot the Linux specific information */
+static int snapshot_os(struct kgsl_device *device,
+ void *snapshot, int remain, void *priv)
+{
+ struct kgsl_snapshot_linux *header = snapshot;
+ struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+ struct task_struct *task;
+ pid_t pid;
+ int hang = (int) priv;
+ int ctxtcount = 0;
+ int size = sizeof(*header);
+
+ /* Figure out how many active contexts there are - these will
+ * be appended on the end of the structure */
+
+ idr_for_each(&device->context_idr, snapshot_context_count, &ctxtcount);
+
+ size += ctxtcount * sizeof(struct kgsl_snapshot_linux_context);
+
+ /* Make sure there is enough room for the data */
+ if (remain < size) {
+ SNAPSHOT_ERR_NOMEM(device, "OS");
+ return 0;
+ }
+
+ memset(header, 0, sizeof(*header));
+
+ header->osid = KGSL_SNAPSHOT_OS_LINUX;
+
+ header->state = hang ? SNAPSHOT_STATE_HUNG : SNAPSHOT_STATE_RUNNING;
+
+ /* Get the kernel build information */
+ strlcpy(header->release, utsname()->release, sizeof(header->release));
+ strlcpy(header->version, utsname()->version, sizeof(header->version));
+
+ /* Get the Unix time for the timestamp */
+ header->seconds = get_seconds();
+
+ /* Remember the power information */
+ header->power_flags = pwr->power_flags;
+ header->power_level = pwr->active_pwrlevel;
+ header->power_interval_timeout = pwr->interval_timeout;
+ header->grpclk = kgsl_get_clkrate(pwr->grp_clks[0]);
+ header->busclk = kgsl_get_clkrate(pwr->ebi1_clk);
+
+ /* Future proof for per-context timestamps */
+ header->current_context = -1;
+
+ /* Get the current PT base */
+ header->ptbase = kgsl_mmu_get_current_ptbase(device);
+ /* And the PID for the task leader */
+ pid = header->pid = kgsl_mmu_get_ptname_from_ptbase(header->ptbase);
+
+ task = find_task_by_vpid(pid);
+
+ if (task)
+ get_task_comm(header->comm, task);
+
+ header->ctxtcount = ctxtcount;
+
+ /* append information for each context */
+ _ctxtptr = snapshot + sizeof(*header);
+ idr_for_each(&device->context_idr, snapshot_context_info, NULL);
+
+ /* Return the size of the data segment */
+ return size;
+}
+/*
+ * kgsl_snapshot_dump_indexed_regs - helper function to dump indexed registers
+ * @device - the device to dump registers from
+ * @snapshot - pointer to the start of the region of memory for the snapshot
+ * @remain - a pointer to the number of bytes remaining in the snapshot
+ * @priv - A pointer to the kgsl_snapshot_indexed_registers data
+ *
+ * Given a indexed register cmd/data pair and a count, dump each indexed
+ * register
+ */
+
+int kgsl_snapshot_dump_indexed_regs(struct kgsl_device *device,
+ void *snapshot, int remain, void *priv)
+{
+ struct kgsl_snapshot_indexed_registers *iregs = priv;
+ struct kgsl_snapshot_indexed_regs *header = snapshot;
+ unsigned int *data = snapshot + sizeof(*header);
+ int i;
+
+ if (remain < (iregs->count * 4) + sizeof(*header)) {
+ SNAPSHOT_ERR_NOMEM(device, "INDEXED REGS");
+ return 0;
+ }
+
+ header->index_reg = iregs->index;
+ header->data_reg = iregs->data;
+ header->count = iregs->count;
+ header->start = iregs->start;
+
+ for (i = 0; i < iregs->count; i++) {
+ kgsl_regwrite(device, iregs->index, iregs->start + i);
+ kgsl_regread(device, iregs->data, &data[i]);
+ }
+
+ return (iregs->count * 4) + sizeof(*header);
+}
+EXPORT_SYMBOL(kgsl_snapshot_dump_indexed_regs);
+
+/*
+ * kgsl_snapshot_dump_regs - helper function to dump device registers
+ * @device - the device to dump registers from
+ * @snapshot - pointer to the start of the region of memory for the snapshot
+ * @remain - a pointer to the number of bytes remaining in the snapshot
+ * @priv - A pointer to the kgsl_snapshot_registers data
+ *
+ * Given an array of register ranges pairs (start,end [inclusive]), dump the
+ * registers into a snapshot register section. The snapshot region stores a
+ * part of dwords for each register - the word address of the register, and
+ * the value.
+ */
+int kgsl_snapshot_dump_regs(struct kgsl_device *device, void *snapshot,
+ int remain, void *priv)
+{
+ struct kgsl_snapshot_regs *header = snapshot;
+ struct kgsl_snapshot_registers *regs = priv;
+ unsigned int *data = snapshot + sizeof(*header);
+ int count = 0, i, j;
+
+ /* Figure out how many registers we are going to dump */
+
+ for (i = 0; i < regs->count; i++) {
+ int start = regs->regs[i * 2];
+ int end = regs->regs[i * 2 + 1];
+
+ count += (end - start + 1);
+ }
+
+ if (remain < (count * 8) + sizeof(*header)) {
+ SNAPSHOT_ERR_NOMEM(device, "REGISTERS");
+ return 0;
+ }
+
+ for (i = 0; i < regs->count; i++) {
+ unsigned int start = regs->regs[i * 2];
+ unsigned int end = regs->regs[i * 2 + 1];
+
+ for (j = start; j <= end; j++) {
+ unsigned int val;
+
+ kgsl_regread(device, j, &val);
+ *data++ = j;
+ *data++ = val;
+ }
+ }
+
+ header->count = count;
+
+ /* Return the size of the section */
+ return (count * 8) + sizeof(*header);
+}
+EXPORT_SYMBOL(kgsl_snapshot_dump_regs);
+
+/*
+ * kgsl_snapshot - construct a device snapshot
+ * @device - device to snapshot
+ * @hang - set to 1 if the snapshot was triggered following a hnag
+ * Given a device, construct a binary snapshot dump of the current device state
+ * and store it in the device snapshot memory.
+ */
+int kgsl_device_snapshot(struct kgsl_device *device, int hang)
+{
+ struct kgsl_snapshot_header *header = device->snapshot;
+ int remain = device->snapshot_maxsize - sizeof(*header);
+ void *snapshot;
+
+ /*
+ * The first hang is always the one we are interested in. To
+ * avoid a subsequent hang blowing away the first, the snapshot
+ * is frozen until it is dumped via sysfs.
+ *
+ * Note that triggered snapshots are always taken regardless
+ * of the state and never frozen.
+ */
+
+ if (hang && device->snapshot_frozen == 1)
+ return 0;
+
+ if (device->snapshot == NULL) {
+ KGSL_DRV_ERR(device,
+ "snapshot: No snapshot memory available\n");
+ return -ENOMEM;
+ }
+
+ if (remain < sizeof(*header)) {
+ KGSL_DRV_ERR(device,
+ "snapshot: Not enough memory for the header\n");
+ return -ENOMEM;
+ }
+
+ header->magic = SNAPSHOT_MAGIC;
+
+ header->gpuid = kgsl_gpuid(device);
+
+ /* Get a pointer to the first section (right after the header) */
+ snapshot = ((void *) device->snapshot) + sizeof(*header);
+
+ /* Build the Linux specific header */
+ snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_OS,
+ snapshot, &remain, snapshot_os, (void *) hang);
+
+ /* Get the device specific sections */
+ if (device->ftbl->snapshot)
+ snapshot = device->ftbl->snapshot(device, snapshot, &remain,
+ hang);
+
+ /* Add the empty end section to let the parser know we are done */
+ snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_END,
+ snapshot, &remain, NULL, NULL);
+
+ device->snapshot_timestamp = get_seconds();
+ device->snapshot_size = (int) (snapshot - device->snapshot);
+
+ /* Freeze the snapshot on a hang until it gets read */
+ device->snapshot_frozen = (hang) ? 1 : 0;
+
+ return 0;
+}
+EXPORT_SYMBOL(kgsl_device_snapshot);
+
+/* An attribute for showing snapshot details */
+struct kgsl_snapshot_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct kgsl_device *device, char *buf);
+ ssize_t (*store)(struct kgsl_device *device, const char *buf,
+ size_t count);
+};
+
+#define to_snapshot_attr(a) \
+container_of(a, struct kgsl_snapshot_attribute, attr)
+
+#define kobj_to_device(a) \
+container_of(a, struct kgsl_device, snapshot_kobj)
+
+/* Dump the sysfs binary data to the user */
+static ssize_t snapshot_show(struct file *filep, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t off,
+ size_t count)
+{
+ struct kgsl_device *device = kobj_to_device(kobj);
+
+ if (device == NULL)
+ return 0;
+
+ /* Return nothing if we haven't taken a snapshot yet */
+ if (device->snapshot_timestamp == 0)
+ return 0;
+
+ /* Get the mutex to keep things from changing while we are dumping */
+ mutex_lock(&device->mutex);
+
+ /*
+ * Release the freeze on the snapshot the first time the buffer is read
+ */
+
+ device->snapshot_frozen = 0;
+
+ if (off >= device->snapshot_size) {
+ count = 0;
+ goto exit;
+ }
+
+ if (off + count > device->snapshot_size)
+ count = device->snapshot_size - off;
+
+ memcpy(buf, device->snapshot + off, count);
+
+exit:
+ mutex_unlock(&device->mutex);
+ return count;
+}
+
+/* Show the timestamp of the last collected snapshot */
+static ssize_t timestamp_show(struct kgsl_device *device, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%x\n", device->snapshot_timestamp);
+}
+
+/* manually trigger a new snapshot to be collected */
+static ssize_t trigger_store(struct kgsl_device *device, const char *buf,
+ size_t count)
+{
+ if (device && count > 0) {
+ mutex_lock(&device->mutex);
+ kgsl_device_snapshot(device, 0);
+ mutex_unlock(&device->mutex);
+ }
+
+ return count;
+}
+
+static struct bin_attribute snapshot_attr = {
+ .attr.name = "dump",
+ .attr.mode = 0444,
+ .size = 0,
+ .read = snapshot_show
+};
+
+#define SNAPSHOT_ATTR(_name, _mode, _show, _store) \
+struct kgsl_snapshot_attribute attr_##_name = { \
+ .attr = { .name = __stringify(_name), .mode = _mode }, \
+ .show = _show, \
+ .store = _store, \
+}
+
+SNAPSHOT_ATTR(trigger, 0600, NULL, trigger_store);
+SNAPSHOT_ATTR(timestamp, 0444, timestamp_show, NULL);
+
+static void snapshot_sysfs_release(struct kobject *kobj)
+{
+}
+
+static ssize_t snapshot_sysfs_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct kgsl_snapshot_attribute *pattr = to_snapshot_attr(attr);
+ struct kgsl_device *device = kobj_to_device(kobj);
+ ssize_t ret;
+
+ if (device && pattr->show)
+ ret = pattr->show(device, buf);
+ else
+ ret = -EIO;
+
+ return ret;
+}
+
+static ssize_t snapshot_sysfs_store(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t count)
+{
+ struct kgsl_snapshot_attribute *pattr = to_snapshot_attr(attr);
+ struct kgsl_device *device = kobj_to_device(kobj);
+ ssize_t ret;
+
+ if (device && pattr->store)
+ ret = pattr->store(device, buf, count);
+ else
+ ret = -EIO;
+
+ return ret;
+}
+
+static const struct sysfs_ops snapshot_sysfs_ops = {
+ .show = snapshot_sysfs_show,
+ .store = snapshot_sysfs_store,
+};
+
+static struct kobj_type ktype_snapshot = {
+ .sysfs_ops = &snapshot_sysfs_ops,
+ .default_attrs = NULL,
+ .release = snapshot_sysfs_release,
+};
+
+/* kgsl_device_snapshot_init - Add resources for the device GPU snapshot
+ * @device - The device to initalize
+ *
+ * Allocate memory for a GPU snapshot for the specified device,
+ * and create the sysfs files to manage it
+ */
+
+int kgsl_device_snapshot_init(struct kgsl_device *device)
+{
+ int ret;
+
+ if (device->snapshot == NULL)
+ device->snapshot = vmalloc(KGSL_SNAPSHOT_MEMSIZE);
+
+ if (device->snapshot == NULL)
+ return -ENOMEM;
+
+ device->snapshot_maxsize = KGSL_SNAPSHOT_MEMSIZE;
+ device->snapshot_timestamp = 0;
+
+ ret = kobject_init_and_add(&device->snapshot_kobj, &ktype_snapshot,
+ &device->dev->kobj, "snapshot");
+ if (ret)
+ goto done;
+
+ ret = sysfs_create_bin_file(&device->snapshot_kobj, &snapshot_attr);
+ if (ret)
+ goto done;
+
+ ret = sysfs_create_file(&device->snapshot_kobj, &attr_trigger.attr);
+ if (ret)
+ goto done;
+
+ ret = sysfs_create_file(&device->snapshot_kobj, &attr_timestamp.attr);
+
+done:
+ return ret;
+}
+EXPORT_SYMBOL(kgsl_device_snapshot_init);
+
+/* kgsl_device_snapshot_close - Take down snapshot memory for a device
+ * @device - Pointer to the kgsl_device
+ *
+ * Remove the sysfs files and free the memory allocated for the GPU
+ * snapshot
+ */
+
+void kgsl_device_snapshot_close(struct kgsl_device *device)
+{
+ sysfs_remove_bin_file(&device->snapshot_kobj, &snapshot_attr);
+ sysfs_remove_file(&device->snapshot_kobj, &attr_trigger.attr);
+ sysfs_remove_file(&device->snapshot_kobj, &attr_timestamp.attr);
+
+ kobject_put(&device->snapshot_kobj);
+
+ vfree(device->snapshot);
+
+ device->snapshot = NULL;
+ device->snapshot_maxsize = 0;
+ device->snapshot_timestamp = 0;
+}
+EXPORT_SYMBOL(kgsl_device_snapshot_close);
diff --git a/drivers/gpu/msm/kgsl_snapshot.h b/drivers/gpu/msm/kgsl_snapshot.h
new file mode 100644
index 0000000..4fdc8a1
--- /dev/null
+++ b/drivers/gpu/msm/kgsl_snapshot.h
@@ -0,0 +1,259 @@
+/* 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 _KGSL_SNAPSHOT_H_
+#define _KGSL_SNAPSHOT_H_
+
+#include <linux/types.h>
+
+/* Snapshot header */
+
+#define SNAPSHOT_MAGIC 0x504D0001
+
+/* GPU ID scheme:
+ * [16:31] - core identifer (0x0002 for 2D or 0x0003 for 3D)
+ * [00:16] - GPU specific identifier
+ */
+
+struct kgsl_snapshot_header {
+ __u32 magic; /* Magic identifier */
+ __u32 gpuid; /* GPU ID - see above */
+} __packed;
+
+/* Section header */
+#define SNAPSHOT_SECTION_MAGIC 0xABCD
+
+struct kgsl_snapshot_section_header {
+ __u16 magic; /* Magic identifier */
+ __u16 id; /* Type of section */
+ __u32 size; /* Size of the section including this header */
+} __packed;
+
+/* Section identifiers */
+#define KGSL_SNAPSHOT_SECTION_OS 0x0101
+#define KGSL_SNAPSHOT_SECTION_REGS 0x0201
+#define KGSL_SNAPSHOT_SECTION_RB 0x0301
+#define KGSL_SNAPSHOT_SECTION_IB 0x0401
+#define KGSL_SNAPSHOT_SECTION_INDEXED_REGS 0x0501
+#define KGSL_SNAPSHOT_SECTION_ISTORE 0x0801
+#define KGSL_SNAPSHOT_SECTION_DEBUG 0x0901
+#define KGSL_SNAPSHOT_SECTION_END 0xFFFF
+
+/* OS sub-section header */
+#define KGSL_SNAPSHOT_OS_LINUX 0x0001
+
+/* Linux OS specific information */
+
+#define SNAPSHOT_STATE_HUNG 0
+#define SNAPSHOT_STATE_RUNNING 1
+
+struct kgsl_snapshot_linux {
+ int osid; /* subsection OS identifier */
+ int state; /* 1 if the thread is running, 0 for hung */
+ __u32 seconds; /* Unix timestamp for the snapshot */
+ __u32 power_flags; /* Current power flags */
+ __u32 power_level; /* Current power level */
+ __u32 power_interval_timeout; /* Power interval timeout */
+ __u32 grpclk; /* Current GP clock value */
+ __u32 busclk; /* Current busclk value */
+ __u32 ptbase; /* Current ptbase */
+ __u32 pid; /* PID of the process that owns the PT */
+ __u32 current_context; /* ID of the current context */
+ __u32 ctxtcount; /* Number of contexts appended to section */
+ unsigned char release[32]; /* kernel release */
+ unsigned char version[32]; /* kernel version */
+ unsigned char comm[16]; /* Name of the process that owns the PT */
+} __packed;
+
+/*
+ * This structure contains a record of an active context.
+ * These are appended one after another in the OS section below
+ * the header above
+ */
+
+struct kgsl_snapshot_linux_context {
+ __u32 id; /* The context ID */
+ __u32 timestamp_queued; /* The last queued timestamp */
+ __u32 timestamp_retired; /* The last timestamp retired by HW */
+};
+
+/* Ringbuffer sub-section header */
+struct kgsl_snapshot_rb {
+ int start; /* dword at the start of the dump */
+ int end; /* dword at the end of the dump */
+ int rbsize; /* Size (in dwords) of the ringbuffer */
+ int wptr; /* Current index of the CPU write pointer */
+ int rptr; /* Current index of the GPU read pointer */
+ int count; /* Number of dwords in the dump */
+} __packed;
+
+/* Indirect buffer sub-section header */
+struct kgsl_snapshot_ib {
+ __u32 gpuaddr; /* GPU address of the the IB */
+ __u32 ptbase; /* Base for the pagetable the GPU address is valid in */
+ int size; /* Size of the IB */
+} __packed;
+
+/* Register sub-section header */
+struct kgsl_snapshot_regs {
+ __u32 count; /* Number of register pairs in the section */
+} __packed;
+
+/* Indexed register sub-section header */
+struct kgsl_snapshot_indexed_regs {
+ __u32 index_reg; /* Offset of the index register for this section */
+ __u32 data_reg; /* Offset of the data register for this section */
+ int start; /* Starting index */
+ int count; /* Number of dwords in the data */
+} __packed;
+
+/* Istore sub-section header */
+struct kgsl_snapshot_istore {
+ int count; /* Number of instructions in the istore */
+} __packed;
+
+/* Debug data sub-section header */
+
+#define SNAPSHOT_DEBUG_SX 1
+#define SNAPSHOT_DEBUG_CP 2
+#define SNAPSHOT_DEBUG_SQ 3
+#define SNAPSHOT_DEBUG_SQTHREAD 4
+#define SNAPSHOT_DEBUG_MIU 5
+
+struct kgsl_snapshot_debug {
+ int type; /* Type identifier for the attached tata */
+ int size; /* Size of the section in bytes */
+} __packed;
+
+#ifdef __KERNEL__
+
+/* Allocate 512K for each device snapshot */
+#define KGSL_SNAPSHOT_MEMSIZE (512 * 1024)
+
+struct kgsl_device;
+/*
+ * A helper macro to print out "not enough memory functions" - this
+ * makes it easy to standardize the messages as well as cut down on
+ * the number of strings in the binary
+ */
+
+#define SNAPSHOT_ERR_NOMEM(_d, _s) \
+ KGSL_DRV_ERR((_d), \
+ "snapshot: not enough snapshot memory for section %s\n", (_s))
+
+/*
+ * kgsl_snapshot_add_section - Add a new section to the GPU snapshot
+ * @device - the KGSL device being snapshotted
+ * @id - the section id
+ * @snapshot - pointer to the memory for the snapshot
+ * @remain - pointer to the number of bytes left in the snapshot region
+ * @func - Function pointer to fill the section
+ * @priv - Priv pointer to pass to the function
+ *
+ * Set up a KGSL snapshot header by filling the memory with the callback
+ * function and adding the standard section header
+ */
+
+static inline void *kgsl_snapshot_add_section(struct kgsl_device *device,
+ u16 id, void *snapshot, int *remain,
+ int (*func)(struct kgsl_device *, void *, int, void *), void *priv)
+{
+ struct kgsl_snapshot_section_header *header = snapshot;
+ void *data = snapshot + sizeof(*header);
+ int ret = 0;
+
+ /*
+ * Sanity check to make sure there is enough for the header. The
+ * callback will check to make sure there is enough for the rest
+ * of the data. If there isn't enough room then don't advance the
+ * pointer.
+ */
+
+ if (*remain < sizeof(*header))
+ return snapshot;
+
+ /* It is legal to have no function (i.e. - make an empty section) */
+
+ if (func) {
+ ret = func(device, data, *remain, priv);
+
+ /*
+ * If there wasn't enough room for the data then don't bother
+ * setting up the header.
+ */
+
+ if (ret == 0)
+ return snapshot;
+ }
+
+ header->magic = SNAPSHOT_SECTION_MAGIC;
+ header->id = id;
+ header->size = ret + sizeof(*header);
+
+ /* Decrement the room left in the snapshot region */
+ *remain -= header->size;
+ /* Advance the pointer to the end of the next function */
+ return snapshot + header->size;
+}
+
+/* A common helper function to dump a range of registers. This will be used in
+ * the GPU specific devices like this:
+ *
+ * struct kgsl_snapshot_registers priv;
+ * priv.regs = registers_array;;
+ * priv.count = num_registers;
+ *
+ * kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS, snapshot,
+ * remain, kgsl_snapshot_dump_regs, &priv).
+ *
+ * Pass in an array of register range pairs in the form of:
+ * start reg, stop reg
+ * All the registers between start and stop inclusive will be dumped
+ */
+
+struct kgsl_snapshot_registers {
+ unsigned int *regs; /* Pointer to the array of register ranges */
+ int count; /* Number of entries in the array */
+};
+
+int kgsl_snapshot_dump_regs(struct kgsl_device *device, void *snapshot,
+ int remain, void *priv);
+
+/*
+ * A common helper function to dump a set of indexed registers. Use it
+ * like this:
+ *
+ * struct kgsl_snapshot_indexed_registers priv;
+ * priv.index = REG_INDEX;
+ * priv.data = REG_DATA;
+ * priv.count = num_registers
+ *
+ * kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_INDEXED_REGS,
+ * snapshot, remain, kgsl_snapshot_dump_indexed_regs, &priv).
+ *
+ * The callback function will write an index from 0 to priv.count to
+ * the index register and read the data from the data register.
+ */
+
+struct kgsl_snapshot_indexed_registers {
+ unsigned int index; /* Offset of the index register */
+ unsigned int data; /* Offset of the data register */
+ unsigned int start; /* Index to start with */
+ unsigned int count; /* Number of values to read from the pair */
+};
+
+int kgsl_snapshot_dump_indexed_regs(struct kgsl_device *device,
+ void *snapshot, int remain, void *priv);
+
+#endif
+#endif
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c
index ac76cde..fa6f4d9 100644
--- a/drivers/input/touchscreen/tsc2007.c
+++ b/drivers/input/touchscreen/tsc2007.c
@@ -81,6 +81,10 @@
u16 max_rt;
unsigned long poll_delay;
unsigned long poll_period;
+ u16 min_x;
+ u16 max_x;
+ u16 min_y;
+ u16 max_y;
bool pendown;
int irq;
@@ -396,6 +400,10 @@
ts->invert_y = pdata->invert_y;
ts->invert_z1 = pdata->invert_z1;
ts->invert_z2 = pdata->invert_z2;
+ ts->min_x = pdata->min_x ? pdata->min_x : 0;
+ ts->max_x = pdata->max_x ? pdata->max_x : MAX_12BIT;
+ ts->min_y = pdata->min_y ? pdata->min_y : 0;
+ ts->max_y = pdata->max_y ? pdata->max_y : MAX_12BIT;
ts->power_shutdown = pdata->power_shutdown;
snprintf(ts->phys, sizeof(ts->phys),
@@ -408,8 +416,10 @@
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
- input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, pdata->fuzzx, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, pdata->fuzzy, 0);
+ input_set_abs_params(input_dev, ABS_X, ts->min_x,
+ ts->max_x, pdata->fuzzx, 0);
+ input_set_abs_params(input_dev, ABS_Y, ts->min_y,
+ ts->max_y, pdata->fuzzy, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT,
pdata->fuzzz, 0);
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index aa0e392..b1dc87e 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -62,7 +62,7 @@
Omni Vision VGA YUV Sensor.
config WEBCAM_OV9726
bool "Sensor OV9726 (VGA Bayer)"
- depends on MSM_CAMERA && (ARCH_MSM8X60 || ARCH_MSM7X30 || ARCH_MSM7X27A) && !MSM_CAMERA_V4L2
+ depends on MSM_CAMERA && (ARCH_MSM8X60 || ARCH_MSM7X30 || ARCH_MSM7X27A)
default n
---help---
Omni Vision VGA Bayer Sensor.
@@ -113,7 +113,7 @@
config MT9E013
bool "Sensor mt9e013 module (BAYER 8M)"
- depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_MSM7X27A) && !MSM_CAMERA_V4L2
+ depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_MSM7X27A)
default n
---help---
Aptina 8M Bayer Sensor modules with Autofocus
@@ -149,6 +149,13 @@
two mipi lanes, required for msm7x2xA platform.
Say Y here if this is msm7x2xA variant platform.
+config DW9712_ACT
+ bool "Lens actuator dw9721"
+ depends on MSM_CAMERA && S5K4E1
+ ---help---
+ dw9721 lens actuator driver for S5K4E1.
+ Say Y here if this is msm7627A variant platform.
+
config MSM_CAMERA_FLASH_SC628A
bool "Qualcomm MSM camera sc628a flash support"
depends on MSM_CAMERA
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 5454763..b91449a 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -15,7 +15,11 @@
obj-$(CONFIG_MSM_CAMERA) += msm_axi_qos.o gemini/
obj-$(CONFIG_MSM_CAMERA_FLASH) += flash.o
obj-$(CONFIG_ARCH_MSM_ARM11) += msm_vfe7x.o msm_io7x.o
-obj-$(CONFIG_ARCH_MSM7X27A) += msm_vfe7x27a.o msm_io_7x27a.o
+ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
+ obj-$(CONFIG_ARCH_MSM7X27A) += msm_vfe7x27a_v4l2.o msm_io_7x27a_v4l2.o
+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
@@ -26,20 +30,20 @@
obj-$(CONFIG_MSM_CAMERA_AF_FOXCONN) += mt9p012_fox.o
obj-$(CONFIG_MSM_CAMERA_AF_BAM) += mt9p012_bam.o
obj-$(CONFIG_MT9P012_KM) += mt9p012_km.o mt9p012_km_reg.o
-obj-$(CONFIG_MT9E013) += mt9e013.o mt9e013_reg.o
obj-$(CONFIG_S5K3E2FX) += s5k3e2fx.o
-obj-$(CONFIG_S5K4E1) += s5k4e1.o s5k4e1_reg.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
obj-$(CONFIG_VX6953) += vx6953.o vx6953_reg.o
obj-$(CONFIG_IMX074) += imx074.o imx074_reg.o
+ obj-$(CONFIG_MT9E013) += mt9e013.o mt9e013_reg.o
+ obj-$(CONFIG_WEBCAM_OV9726) += ov9726.o ov9726_reg.o
+ obj-$(CONFIG_S5K4E1) += s5k4e1.o s5k4e1_reg.o
endif
obj-$(CONFIG_QS_S5K4E1) += qs_s5k4e1.o qs_s5k4e1_reg.o
obj-$(CONFIG_VB6801) += vb6801.o
obj-$(CONFIG_IMX072) += imx072.o imx072_reg.o
-obj-$(CONFIG_WEBCAM_OV9726) += ov9726.o ov9726_reg.o
obj-$(CONFIG_WEBCAM_OV7692) += ov7692.o
obj-$(CONFIG_WEBCAM_OV7692_QRD) += ov7692_qrd.o
obj-$(CONFIG_OV5640) += ov5640.o
diff --git a/drivers/media/video/msm/actuators/Makefile b/drivers/media/video/msm/actuators/Makefile
index 4f4d5ee..f0a0c69 100644
--- a/drivers/media/video/msm/actuators/Makefile
+++ b/drivers/media/video/msm/actuators/Makefile
@@ -3,3 +3,4 @@
EXTRA_CFLAGS += -Idrivers/media/video/msm/io
obj-$(CONFIG_MSM_ACTUATOR) += msm_actuator.o
obj-$(CONFIG_IMX074_ACT) += imx074_act.o
+obj-$(CONFIG_DW9712_ACT) += dw9712_act.o
diff --git a/drivers/media/video/msm/actuators/dw9712_act.c b/drivers/media/video/msm/actuators/dw9712_act.c
new file mode 100644
index 0000000..562290f
--- /dev/null
+++ b/drivers/media/video/msm/actuators/dw9712_act.c
@@ -0,0 +1,277 @@
+/* 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 "msm_actuator.h"
+#include "msm_camera_i2c.h"
+
+#define DW9712_TOTAL_STEPS_NEAR_TO_FAR 32
+DEFINE_MUTEX(dw9712_act_mutex);
+static struct msm_actuator_ctrl_t dw9712_act_t;
+
+static struct region_params_t g_regions[] = {
+ /* step_bound[0] - macro side boundary
+ * step_bound[1] - infinity side boundary
+ */
+ /* Region 1 */
+ {
+ .step_bound = {DW9712_TOTAL_STEPS_NEAR_TO_FAR, 0},
+ .code_per_step = 2,
+ },
+};
+
+static uint16_t g_scenario[] = {
+ /* MOVE_NEAR and MOVE_FAR dir*/
+ DW9712_TOTAL_STEPS_NEAR_TO_FAR,
+};
+
+static int32_t dw9712_af_i2c_txdata(unsigned short saddr,
+ unsigned char *txdata, int length,
+ struct msm_actuator_ctrl_t *a_ctrl)
+{
+ struct i2c_msg msg[] = {
+ {
+ .addr = saddr,
+ .flags = 0,
+ .len = length,
+ .buf = txdata,
+ },
+ };
+ if (i2c_transfer(a_ctrl->i2c_client.client->adapter, msg, 1) < 0) {
+ pr_err("s5k4e1_af_i2c_txdata faild 0x%x\n", saddr);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int32_t dw9712_af_i2c_write_b_sensor(struct msm_actuator_ctrl_t *a_ctrl,
+ uint8_t waddr, uint8_t bdata)
+{
+ int32_t rc = -EFAULT;
+ unsigned char buf[2];
+
+ memset(buf, 0, sizeof(buf));
+ buf[0] = waddr;
+ buf[1] = bdata;
+ rc = dw9712_af_i2c_txdata(a_ctrl->i2c_addr, buf, 2, a_ctrl);
+ if (rc < 0) {
+ pr_err("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+ waddr, bdata);
+ }
+ return rc;
+}
+
+static int32_t dw9712_wrapper_i2c_write(struct msm_actuator_ctrl_t *a_ctrl,
+ int16_t next_lens_position, void *params)
+{
+ uint8_t msb, lsb;
+
+ msb = (next_lens_position & 0xFF00) >> 8;
+ lsb = next_lens_position & 0xFF;
+ dw9712_af_i2c_write_b_sensor(a_ctrl, msb, lsb);
+
+ return 0;
+}
+
+int32_t msm_dw9712_act_move_focus(
+ struct msm_actuator_ctrl_t *a_ctrl,
+ int dir,
+ int32_t num_steps)
+{
+ int32_t rc = 0;
+ int8_t sign_dir = 0;
+ int16_t dest_step_pos = 0;
+ uint8_t code_val_msb, code_val_lsb;
+ uint16_t code_val;
+
+ LINFO("%s called, dir %d, num_steps %d\n",
+ __func__,
+ dir,
+ num_steps);
+
+ /* Determine sign direction */
+ if (dir == MOVE_NEAR)
+ sign_dir = 1;
+ else if (dir == MOVE_FAR)
+ sign_dir = -1;
+ else {
+ pr_err("Illegal focus direction\n");
+ rc = -EINVAL;
+ return rc;
+ }
+
+ /* Determine destination step position */
+ dest_step_pos = a_ctrl->curr_step_pos +
+ (sign_dir * num_steps);
+
+ if (dest_step_pos < 0)
+ dest_step_pos = 0;
+ else if (dest_step_pos > 1023)
+ dest_step_pos = 1023;
+
+ if (dest_step_pos == a_ctrl->curr_step_pos)
+ return rc;
+
+ code_val_msb = dest_step_pos >> 4;
+ code_val_lsb = (dest_step_pos & 0x000F) << 4;
+ code_val = (code_val_msb << 8) | (code_val_lsb);
+ rc = dw9712_wrapper_i2c_write(a_ctrl, code_val, NULL);
+ if (rc >= 0) {
+ rc = 0;
+ a_ctrl->curr_step_pos = dest_step_pos;
+ }
+ return 0;
+}
+
+static int32_t dw9712_set_default_focus(
+ struct msm_actuator_ctrl_t *a_ctrl)
+{
+ int32_t rc = 0;
+
+ if (!a_ctrl->step_position_table)
+ a_ctrl->func_tbl.actuator_init_table(a_ctrl);
+
+ if (a_ctrl->curr_step_pos != 0) {
+ rc = a_ctrl->func_tbl.actuator_move_focus(a_ctrl,
+ MOVE_FAR, a_ctrl->curr_step_pos);
+ a_ctrl->curr_step_pos = 0;
+ } else
+ rc = dw9712_wrapper_i2c_write(a_ctrl, 0x00, NULL);
+ if (rc >= 0)
+ rc = 0;
+ return rc;
+}
+
+static const struct i2c_device_id dw9712_act_i2c_id[] = {
+ {"dw9712_act", (kernel_ulong_t)&dw9712_act_t},
+ { }
+};
+
+static int dw9712_act_config(void __user *argp)
+{
+ LINFO("%s called\n", __func__);
+ return (int) msm_actuator_config(&dw9712_act_t, argp);
+}
+
+static int dw9712_i2c_add_driver_table(void)
+{
+ LINFO("%s called\n", __func__);
+ return (int) msm_actuator_init_table(&dw9712_act_t);
+}
+
+static struct i2c_driver dw9712_act_i2c_driver = {
+ .id_table = dw9712_act_i2c_id,
+ .probe = msm_actuator_i2c_probe,
+ .remove = __exit_p(dw9712_act_i2c_remove),
+ .driver = {
+ .name = "dw9712_act",
+ },
+};
+
+static int __init dw9712_i2c_add_driver(void)
+{
+ int rc = 0;
+
+ LINFO("%s called :%x\n", __func__, dw9712_act_t.i2c_addr);
+ rc = i2c_add_driver(dw9712_act_t.i2c_driver);
+ LINFO("%s called:%d %x\n", __func__, rc, dw9712_act_t.i2c_addr);
+ return rc;
+}
+
+static struct v4l2_subdev_core_ops dw9712_act_subdev_core_ops;
+
+static struct v4l2_subdev_ops dw9712_act_subdev_ops = {
+ .core = &dw9712_act_subdev_core_ops,
+};
+
+static int32_t dw9712_act_create_subdevice(
+ void *board_info,
+ void *sdev)
+{
+ int rc = 0;
+
+ struct msm_actuator_info *ptr;
+ LINFO("%s called\n", __func__);
+
+ ptr = board_info;
+ dw9712_act_t.vcm_pwd = ptr->vcm_pwd;
+ dw9712_act_t.vcm_enable = ptr->vcm_enable;
+ LINFO("vcm info: %x %x\n", dw9712_act_t.vcm_pwd,
+ dw9712_act_t.vcm_enable);
+ if (dw9712_act_t.vcm_enable) {
+ rc = gpio_request(dw9712_act_t.vcm_pwd, "dw9712_af");
+ if (!rc) {
+ LINFO("Enable VCM PWD\n");
+ gpio_direction_output(dw9712_act_t.vcm_pwd, 1);
+ }
+ }
+ return (int) msm_actuator_create_subdevice(&dw9712_act_t,
+ ptr->board_info,
+ (struct v4l2_subdev *)sdev);
+}
+
+static struct msm_actuator_ctrl_t dw9712_act_t = {
+ .i2c_driver = &dw9712_act_i2c_driver,
+ .i2c_addr = 0x8C,
+ .act_v4l2_subdev_ops = &dw9712_act_subdev_ops,
+ .actuator_ext_ctrl = {
+ .a_init_table = dw9712_i2c_add_driver_table,
+ .a_create_subdevice = dw9712_act_create_subdevice,
+ .a_config = dw9712_act_config,
+ },
+
+ .i2c_client = {
+ .addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+ },
+
+ .set_info = {
+ .total_steps = DW9712_TOTAL_STEPS_NEAR_TO_FAR,
+ },
+
+ .curr_step_pos = 0,
+ .curr_region_index = 0,
+ .initial_code = 0x0,
+ .actuator_mutex = &dw9712_act_mutex,
+
+ .func_tbl = {
+ .actuator_init_table = msm_actuator_init_table,
+ .actuator_move_focus = msm_dw9712_act_move_focus,
+ .actuator_set_default_focus = dw9712_set_default_focus,
+ .actuator_i2c_write = dw9712_wrapper_i2c_write,
+ },
+
+ .get_info = {
+ .focal_length_num = 46,
+ .focal_length_den = 10,
+ .f_number_num = 265,
+ .f_number_den = 100,
+ .f_pix_num = 14,
+ .f_pix_den = 10,
+ .total_f_dist_num = 197681,
+ .total_f_dist_den = 1000,
+ },
+
+ /* Initialize scenario */
+ .ringing_scenario[MOVE_NEAR] = g_scenario,
+ .scenario_size[MOVE_NEAR] = ARRAY_SIZE(g_scenario),
+ .ringing_scenario[MOVE_FAR] = g_scenario,
+ .scenario_size[MOVE_FAR] = ARRAY_SIZE(g_scenario),
+
+ /* Initialize region params */
+ .region_params = g_regions,
+ .region_size = ARRAY_SIZE(g_regions),
+};
+
+subsys_initcall(dw9712_i2c_add_driver);
+MODULE_DESCRIPTION("DW9712 actuator");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/actuators/imx074_act.c b/drivers/media/video/msm/actuators/imx074_act.c
index e01d2c7..e4d340d4 100644
--- a/drivers/media/video/msm/actuators/imx074_act.c
+++ b/drivers/media/video/msm/actuators/imx074_act.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-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
@@ -186,13 +186,14 @@
};
static int32_t imx074_act_create_subdevice(
- void *board_info,
+ void *act_info,
void *sdev)
{
+ struct msm_actuator_info *info = (struct msm_actuator_info *)act_info;
LINFO("%s called\n", __func__);
return (int) msm_actuator_create_subdevice(&imx074_act_t,
- (struct i2c_board_info const *)board_info,
+ (struct i2c_board_info const *)info->board_info,
(struct v4l2_subdev *)sdev);
}
diff --git a/drivers/media/video/msm/actuators/msm_actuator.h b/drivers/media/video/msm/actuators/msm_actuator.h
index 6fad8dd..9c90282 100644
--- a/drivers/media/video/msm/actuators/msm_actuator.h
+++ b/drivers/media/video/msm/actuators/msm_actuator.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-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
@@ -14,6 +14,7 @@
#include <linux/i2c.h>
#include <mach/camera.h>
+#include <mach/gpio.h>
#include <media/v4l2-subdev.h>
#include <media/msm_camera.h>
#include "msm_camera_i2c.h"
@@ -100,6 +101,8 @@
uint16_t region_size;
struct damping_t *damping[2];
void *user_data;
+ uint32_t vcm_pwd;
+ uint32_t vcm_enable;
};
int32_t msm_actuator_i2c_write_b_af(struct msm_actuator_ctrl_t *a_ctrl,
diff --git a/drivers/media/video/msm/csi/Makefile b/drivers/media/video/msm/csi/Makefile
index 3ce81af..6e8eb122 100644
--- a/drivers/media/video/msm/csi/Makefile
+++ b/drivers/media/video/msm/csi/Makefile
@@ -1,3 +1,4 @@
GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
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
diff --git a/drivers/media/video/msm/csi/msm_csic.c b/drivers/media/video/msm/csi/msm_csic.c
new file mode 100644
index 0000000..476615d
--- /dev/null
+++ b/drivers/media/video/msm/csi/msm_csic.c
@@ -0,0 +1,430 @@
+/* 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/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <mach/board.h>
+#include <mach/camera.h>
+#include <media/msm_isp.h>
+#include "msm_csic.h"
+#include "msm.h"
+
+#define DBG_CSIC 0
+
+#define V4L2_IDENT_CSIC 50004
+/* MIPI CSI controller registers */
+#define MIPI_PHY_CONTROL 0x00000000
+#define MIPI_PROTOCOL_CONTROL 0x00000004
+#define MIPI_INTERRUPT_STATUS 0x00000008
+#define MIPI_INTERRUPT_MASK 0x0000000C
+#define MIPI_CAMERA_CNTL 0x00000024
+#define MIPI_CALIBRATION_CONTROL 0x00000018
+#define MIPI_PHY_D0_CONTROL2 0x00000038
+#define MIPI_PHY_D1_CONTROL2 0x0000003C
+#define MIPI_PHY_D2_CONTROL2 0x00000040
+#define MIPI_PHY_D3_CONTROL2 0x00000044
+#define MIPI_PHY_CL_CONTROL 0x00000048
+#define MIPI_PHY_D0_CONTROL 0x00000034
+#define MIPI_PHY_D1_CONTROL 0x00000020
+#define MIPI_PHY_D2_CONTROL 0x0000002C
+#define MIPI_PHY_D3_CONTROL 0x00000030
+#define MIPI_PWR_CNTL 0x00000054
+
+/*
+ * MIPI_PROTOCOL_CONTROL register bits to enable/disable the features of
+ * CSI Rx Block
+ */
+
+/* DPCM scheme */
+#define MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT 0x1e
+/* SW_RST to issue a SW reset to the CSI core */
+#define MIPI_PROTOCOL_CONTROL_SW_RST_BMSK 0x8000000
+/* To Capture Long packet Header Info in MIPI_PROTOCOL_STATUS register */
+#define MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK 0x200000
+/* 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
+/* Enable error correction on packet headers */
+#define MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK 0x20000
+
+/*
+ * MIPI_CALIBRATION_CONTROL register contains control info for
+ * calibration impledence controller
+*/
+
+/* Enable bit for calibration pad */
+#define MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT 0x16
+/* With SWCAL_STRENGTH_OVERRIDE_EN, SW_CAL_EN and MANUAL_OVERRIDE_EN
+ * the hardware calibration circuitry associated with CAL_SW_HW_MODE
+ * is bypassed
+*/
+#define MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT 0x15
+/* To indicate the Calibration process is in the control of HW/SW */
+#define MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT 0x14
+/* When this is set the strength value of the data and clk lane impedence
+ * termination is updated with MANUAL_STRENGTH settings and calibration
+ * sensing logic is idle.
+*/
+#define MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT 0x7
+
+/* Data lane0 control */
+/* T-hs Settle count value for Rx */
+#define MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT 0x18
+/* Rx termination control */
+#define MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT 0x10
+/* LP Rx enable */
+#define MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT 0x4
+/*
+ * Enable for error in sync sequence
+ * 1 - one bit error in sync seq
+ * 0 - requires all 8 bit correct seq
+*/
+#define MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3
+
+/* Comments are same as D0 */
+#define MIPI_PHY_D1_CONTROL2_SETTLE_COUNT_SHFT 0x18
+#define MIPI_PHY_D1_CONTROL2_HS_TERM_IMP_SHFT 0x10
+#define MIPI_PHY_D1_CONTROL2_LP_REC_EN_SHFT 0x4
+#define MIPI_PHY_D1_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3
+
+/* Comments are same as D0 */
+#define MIPI_PHY_D2_CONTROL2_SETTLE_COUNT_SHFT 0x18
+#define MIPI_PHY_D2_CONTROL2_HS_TERM_IMP_SHFT 0x10
+#define MIPI_PHY_D2_CONTROL2_LP_REC_EN_SHFT 0x4
+#define MIPI_PHY_D2_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3
+
+/* Comments are same as D0 */
+#define MIPI_PHY_D3_CONTROL2_SETTLE_COUNT_SHFT 0x18
+#define MIPI_PHY_D3_CONTROL2_HS_TERM_IMP_SHFT 0x10
+#define MIPI_PHY_D3_CONTROL2_LP_REC_EN_SHFT 0x4
+#define MIPI_PHY_D3_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3
+
+/* PHY_CL_CTRL programs the parameters of clk lane of CSIRXPHY */
+/* HS Rx termination control */
+#define MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT 0x18
+/* Start signal for T-hs delay */
+#define MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT 0x2
+
+/* PHY DATA lane 0 control */
+/*
+ * HS RX equalizer strength control
+ * 00 - 0db 01 - 3db 10 - 5db 11 - 7db
+*/
+#define MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT 0x1c
+/* PHY DATA lane 1 control */
+/* Shutdown signal for MIPI clk phy line */
+#define MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT 0x9
+/* Shutdown signal for MIPI data phy line */
+#define MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT 0x8
+
+#define MSM_AXI_QOS_PREVIEW 200000
+#define MSM_AXI_QOS_SNAPSHOT 200000
+#define MSM_AXI_QOS_RECORDING 200000
+
+#define MIPI_PWR_CNTL_ENA 0x07
+#define MIPI_PWR_CNTL_DIS 0x0
+
+static int msm_csic_config(struct csic_cfg_params *cfg_params)
+{
+ int rc = 0;
+ uint32_t val = 0;
+ struct csic_device *csic_dev;
+ struct msm_camera_csi_params *csic_params;
+ void __iomem *csicbase;
+
+ csic_dev = v4l2_get_subdevdata(cfg_params->subdev);
+ csicbase = csic_dev->base;
+ csic_params = cfg_params->parms;
+
+ /* Enable error correction for DATA lane. Applies to all data lanes */
+ msm_io_w(0x4, csicbase + MIPI_PHY_CONTROL);
+
+ msm_io_w(MIPI_PROTOCOL_CONTROL_SW_RST_BMSK,
+ csicbase + MIPI_PROTOCOL_CONTROL);
+
+ val = MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK |
+ MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK |
+ MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK;
+ val |= (uint32_t)(csic_params->data_format) <<
+ MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT;
+ val |= csic_params->dpcm_scheme <<
+ MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT;
+ CDBG("%s MIPI_PROTOCOL_CONTROL val=0x%x\n", __func__, val);
+ msm_io_w(val, csicbase + MIPI_PROTOCOL_CONTROL);
+
+ val = (0x1 << MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT) |
+ (0x1 <<
+ MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT) |
+ (0x1 << MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT) |
+ (0x1 << MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT);
+ CDBG("%s MIPI_CALIBRATION_CONTROL val=0x%x\n", __func__, val);
+ msm_io_w(val, csicbase + MIPI_CALIBRATION_CONTROL);
+
+ val = (csic_params->settle_cnt <<
+ MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) |
+ (0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) |
+ (0x1 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) |
+ (0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT);
+ CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
+ msm_io_w(val, csicbase + MIPI_PHY_D0_CONTROL2);
+ msm_io_w(val, csicbase + MIPI_PHY_D1_CONTROL2);
+ msm_io_w(val, csicbase + MIPI_PHY_D2_CONTROL2);
+ msm_io_w(val, csicbase + MIPI_PHY_D3_CONTROL2);
+
+
+ val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) |
+ (0x1 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT);
+ CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
+ msm_io_w(val, csicbase + MIPI_PHY_CL_CONTROL);
+
+ val = 0 << MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT;
+ msm_io_w(val, csicbase + MIPI_PHY_D0_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, csicbase + MIPI_PHY_D1_CONTROL);
+
+ msm_io_w(0x00000000, csicbase + MIPI_PHY_D2_CONTROL);
+ msm_io_w(0x00000000, csicbase + MIPI_PHY_D3_CONTROL);
+
+ /* program number of lanes and lane mapping */
+ switch (csic_params->lane_cnt) {
+ case 1:
+ msm_io_w(csic_params->lane_assign << 8 | 0x4,
+ csicbase + MIPI_CAMERA_CNTL);
+ break;
+ case 2:
+ msm_io_w(csic_params->lane_assign << 8 | 0x5,
+ csicbase + MIPI_CAMERA_CNTL);
+ break;
+ case 3:
+ msm_io_w(csic_params->lane_assign << 8 | 0x6,
+ csicbase + MIPI_CAMERA_CNTL);
+ break;
+ case 4:
+ msm_io_w(csic_params->lane_assign << 8 | 0x7,
+ csicbase + MIPI_CAMERA_CNTL);
+ 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);
+
+ return rc;
+}
+
+static irqreturn_t msm_csic_irq(int irq_num, void *data)
+{
+ uint32_t irq;
+ struct csic_device *csic_dev = data;
+
+ pr_info("msm_csic_irq: %x\n", (unsigned int)csic_dev->base);
+ irq = msm_io_r(csic_dev->base + MIPI_INTERRUPT_STATUS);
+ pr_info("%s MIPI_INTERRUPT_STATUS = 0x%x\n", __func__, irq);
+ msm_io_w(irq, csic_dev->base + MIPI_INTERRUPT_STATUS);
+
+ /* TODO: Needs to send this info to upper layers */
+ if ((irq >> 19) & 0x1)
+ pr_info("Unsupported packet format is received\n");
+ return IRQ_HANDLED;
+}
+
+static int msm_csic_subdev_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ BUG_ON(!chip);
+ chip->ident = V4L2_IDENT_CSIC;
+ chip->revision = 0;
+ return 0;
+}
+
+static struct msm_cam_clk_info csic_clk_info[] = {
+ {"csi_clk", 400000000},
+ {"csi_vfe_clk", -1},
+ {"csi_pclk", -1},
+};
+
+static int msm_csic_init(struct v4l2_subdev *sd, uint32_t *csic_version)
+{
+ int rc = 0;
+ struct csic_device *csic_dev;
+ csic_dev = v4l2_get_subdevdata(sd);
+ if (csic_dev == NULL) {
+ rc = -ENOMEM;
+ return rc;
+ }
+
+ csic_dev->base = ioremap(csic_dev->mem->start,
+ resource_size(csic_dev->mem));
+ if (!csic_dev->base) {
+ rc = -ENOMEM;
+ 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);
+ if (rc < 0) {
+ iounmap(csic_dev->base);
+ return rc;
+ }
+
+#if DBG_CSIC
+ enable_irq(csic_dev->irq->start);
+#endif
+
+ return 0;
+}
+
+static int msm_csic_release(struct v4l2_subdev *sd)
+{
+ struct csic_device *csic_dev;
+ csic_dev = v4l2_get_subdevdata(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);
+
+ iounmap(csic_dev->base);
+ return 0;
+}
+
+static long msm_csic_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg)
+{
+ struct csic_cfg_params cfg_params;
+ switch (cmd) {
+ case VIDIOC_MSM_CSIC_CFG:
+ cfg_params.subdev = sd;
+ cfg_params.parms = arg;
+ return msm_csic_config((struct csic_cfg_params *)&cfg_params);
+ case VIDIOC_MSM_CSIC_INIT:
+ return msm_csic_init(sd, (uint32_t *)arg);
+ case VIDIOC_MSM_CSIC_RELEASE:
+ return msm_csic_release(sd);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+static struct v4l2_subdev_core_ops msm_csic_subdev_core_ops = {
+ .g_chip_ident = &msm_csic_subdev_g_chip_ident,
+ .ioctl = &msm_csic_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_csic_subdev_ops = {
+ .core = &msm_csic_subdev_core_ops,
+};
+
+static int __devinit csic_probe(struct platform_device *pdev)
+{
+ struct csic_device *new_csic_dev;
+ int rc = 0;
+ CDBG("%s: device id = %d\n", __func__, pdev->id);
+ new_csic_dev = kzalloc(sizeof(struct csic_device), GFP_KERNEL);
+ if (!new_csic_dev) {
+ pr_err("%s: no enough memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ v4l2_subdev_init(&new_csic_dev->subdev, &msm_csic_subdev_ops);
+ v4l2_set_subdevdata(&new_csic_dev->subdev, new_csic_dev);
+ platform_set_drvdata(pdev, &new_csic_dev->subdev);
+ mutex_init(&new_csic_dev->mutex);
+
+ new_csic_dev->mem = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "csic");
+ if (!new_csic_dev->mem) {
+ pr_err("%s: no mem resource?\n", __func__);
+ rc = -ENODEV;
+ goto csic_no_resource;
+ }
+ new_csic_dev->irq = platform_get_resource_byname(pdev,
+ IORESOURCE_IRQ, "csic");
+ if (!new_csic_dev->irq) {
+ pr_err("%s: no irq resource?\n", __func__);
+ rc = -ENODEV;
+ goto csic_no_resource;
+ }
+ new_csic_dev->io = request_mem_region(new_csic_dev->mem->start,
+ resource_size(new_csic_dev->mem), pdev->name);
+ if (!new_csic_dev->io) {
+ pr_err("%s: no valid mem region\n", __func__);
+ rc = -EBUSY;
+ goto csic_no_resource;
+ }
+
+ rc = request_irq(new_csic_dev->irq->start, msm_csic_irq,
+ IRQF_TRIGGER_RISING, "csic", new_csic_dev);
+ if (rc < 0) {
+ release_mem_region(new_csic_dev->mem->start,
+ resource_size(new_csic_dev->mem));
+ pr_err("%s: irq request fail\n", __func__);
+ rc = -EBUSY;
+ 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;
+ return 0;
+
+csic_no_resource:
+ mutex_destroy(&new_csic_dev->mutex);
+ kfree(new_csic_dev);
+ return 0;
+}
+
+static struct platform_driver csic_driver = {
+ .probe = csic_probe,
+ .driver = {
+ .name = MSM_CSIC_DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_csic_init_module(void)
+{
+ return platform_driver_register(&csic_driver);
+}
+
+static void __exit msm_csic_exit_module(void)
+{
+ platform_driver_unregister(&csic_driver);
+}
+
+module_init(msm_csic_init_module);
+module_exit(msm_csic_exit_module);
+MODULE_DESCRIPTION("MSM csic driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/csi/msm_csic.h b/drivers/media/video/msm/csi/msm_csic.h
new file mode 100644
index 0000000..08dde52
--- /dev/null
+++ b/drivers/media/video/msm/csi/msm_csic.h
@@ -0,0 +1,48 @@
+/* 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_CSIC_H
+#define MSM_CSIC_H
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <media/v4l2-subdev.h>
+
+struct csic_device {
+ struct platform_device *pdev;
+ struct v4l2_subdev subdev;
+ struct resource *mem;
+ struct resource *irq;
+ struct resource *io;
+ void __iomem *base;
+ struct mutex mutex;
+ uint32_t hw_version;
+
+ struct clk *csic_clk[5];
+};
+
+struct csic_cfg_params {
+ struct v4l2_subdev *subdev;
+ void *parms;
+};
+
+#define VIDIOC_MSM_CSIC_CFG \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct csic_cfg_params)
+
+#define VIDIOC_MSM_CSIC_INIT \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct v4l2_subdev*)
+
+#define VIDIOC_MSM_CSIC_RELEASE \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct v4l2_subdev*)
+
+#endif
+
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 363e437..a9aa28b 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -1478,15 +1478,14 @@
__func__, rc);
return rc;
}
- rc = v4l2_device_register_subdev(&pcam->v4l2_dev,
- pcam->mctl.isp_sdev->sd_vpe);
- if (rc < 0) {
- mutex_unlock(&pcam->vid_lock);
- pr_err("%s: vpe v4l2_device_register_subdev failed rc = %d\n",
- __func__, rc);
- return rc;
+ if (pcam->mctl.isp_sdev->sd_vpe) {
+ rc = v4l2_device_register_subdev(&pcam->v4l2_dev,
+ pcam->mctl.isp_sdev->sd_vpe);
+ if (rc < 0) {
+ mutex_unlock(&pcam->vid_lock);
+ return rc;
+ }
}
-
rc = msm_setup_v4l2_event_queue(&pcam_inst->eventHandle,
pcam->pvdev);
if (rc < 0) {
@@ -2395,7 +2394,7 @@
goto client_fail;
*actctrl = *a_ext_ctrl;
- a_ext_ctrl->a_create_subdevice((void *)actuator_info->board_info,
+ a_ext_ctrl->a_create_subdevice((void *)actuator_info,
(void *)act_sdev);
return rc;
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 5fc3e6a..cc2e8b4 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-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
@@ -43,6 +43,7 @@
#define MSM_CSIPHY_DRV_NAME "msm_csiphy"
#define MSM_CSID_DRV_NAME "msm_csid"
+#define MSM_CSIC_DRV_NAME "msm_csic"
#define MSM_ISPIF_DRV_NAME "msm_ispif"
#define MSM_VFE_DRV_NAME "msm_vfe"
#define MSM_VPE_DRV_NAME "msm_vpe"
@@ -121,6 +122,8 @@
NOTIFY_PCLK_CHANGE, /* arg = pclk */
NOTIFY_CSIPHY_CFG, /* arg = msm_camera_csiphy_params */
NOTIFY_CSID_CFG, /* arg = msm_camera_csid_params */
+ NOTIFY_CSIC_CFG, /* arg = msm_camera_csic_params */
+ NOTIFY_VFE_BUF_FREE_EVT, /* arg = msm_camera_csic_params */
NOTIFY_INVALID
};
@@ -225,6 +228,7 @@
struct msm_cam_config_dev *config_device;
struct v4l2_subdev *csiphy_sdev; /*csiphy sub device*/
struct v4l2_subdev *csid_sdev; /*csid sub device*/
+ struct v4l2_subdev *csic_sdev; /*csid sub device*/
struct v4l2_subdev *ispif_sdev; /* ispif sub device */
struct v4l2_subdev *act_sdev; /* actuator sub device */
diff --git a/drivers/media/video/msm/msm_io_7x27a_v4l2.c b/drivers/media/video/msm/msm_io_7x27a_v4l2.c
new file mode 100644
index 0000000..bee9f49
--- /dev/null
+++ b/drivers/media/video/msm/msm_io_7x27a_v4l2.c
@@ -0,0 +1,258 @@
+/* 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/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/pm_qos_params.h>
+#include <mach/board.h>
+#include <mach/camera.h>
+#include <mach/camera.h>
+#include <mach/clk.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+
+
+#define MSM_AXI_QOS_PREVIEW 200000
+#define MSM_AXI_QOS_SNAPSHOT 200000
+#define MSM_AXI_QOS_RECORDING 200000
+
+static struct clk *camio_cam_clk;
+static struct resource *clk_ctrl_mem;
+static struct msm_camera_io_clk camio_clk;
+void __iomem *appbase;
+
+void msm_io_w(u32 data, void __iomem *addr)
+{
+ CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+ writel_relaxed((data), (addr));
+}
+
+u32 msm_io_r(void __iomem *addr)
+{
+ uint32_t data = readl_relaxed(addr);
+ CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+ return data;
+}
+
+void msm_camio_clk_rate_set_2(struct clk *clk, int rate)
+{
+ clk_set_rate(clk, rate);
+}
+int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
+{
+ int rc = 0;
+ struct clk *clk = NULL;
+
+ switch (clktype) {
+ case CAMIO_CAM_MCLK_CLK:
+ clk = clk_get(NULL, "cam_m_clk");
+ camio_cam_clk = clk;
+ msm_camio_clk_rate_set_2(clk, camio_clk.mclk_clk_rate);
+ break;
+ default:
+ break;
+ }
+
+ if (!IS_ERR(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_CAM_MCLK_CLK:
+ clk = camio_cam_clk;
+ break;
+ default:
+ break;
+ }
+
+ if (!IS_ERR(clk)) {
+ clk_disable(clk);
+ clk_put(clk);
+ } else
+ rc = -1;
+ return rc;
+}
+
+void msm_camio_clk_rate_set(int rate)
+{
+ struct clk *clk = camio_cam_clk;
+ clk_set_rate(clk, rate);
+}
+
+int msm_sensor_probe_on(struct device *dev)
+{
+ int rc = 0;
+ struct msm_camera_sensor_info *sinfo = dev->platform_data;
+ struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+ camio_clk = camdev->ioclk;
+
+ rc = camdev->camera_gpio_on();
+ if (rc < 0)
+ return rc;
+
+ rc = msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
+ if (rc < 0)
+ camdev->camera_gpio_off();
+
+ return rc;
+}
+
+int msm_sensor_probe_off(struct device *dev)
+{
+ struct msm_camera_sensor_info *sinfo = dev->platform_data;
+ struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+ camdev->camera_gpio_off();
+ return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
+}
+
+void msm_camio_vfe_blk_reset(void)
+{
+ uint32_t val;
+
+ /* do apps reset */
+ val = readl_relaxed(appbase + 0x00000210);
+ val |= 0x1;
+ writel_relaxed(val, appbase + 0x00000210);
+ usleep_range(10000, 11000);
+
+ val = readl_relaxed(appbase + 0x00000210);
+ val &= ~0x1;
+ writel_relaxed(val, appbase + 0x00000210);
+ usleep_range(10000, 11000);
+
+ /* do axi reset */
+ val = readl_relaxed(appbase + 0x00000208);
+ val |= 0x1;
+ writel_relaxed(val, appbase + 0x00000208);
+ usleep_range(10000, 11000);
+
+ val = readl_relaxed(appbase + 0x00000208);
+ val &= ~0x1;
+ writel_relaxed(val, appbase + 0x00000208);
+ mb();
+ usleep_range(10000, 11000);
+}
+
+int msm_camio_probe_on(struct platform_device *pdev)
+{
+ int rc = 0;
+ const struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+ struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+ camio_clk = camdev->ioclk;
+
+ rc = camdev->camera_gpio_on();
+ if (rc < 0)
+ return rc;
+ return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
+}
+
+int msm_camio_probe_off(struct platform_device *pdev)
+{
+ const struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+ struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+ camdev->camera_gpio_off();
+ return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
+}
+
+void msm_camio_set_perf_lvl(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__);
+ }
+}
+
+static int __devinit clkctl_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+
+ clk_ctrl_mem = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "clk_ctl");
+ if (!clk_ctrl_mem) {
+ pr_err("%s: no mem resource:3?\n", __func__);
+ return -ENODEV;
+ }
+
+ appbase = ioremap(clk_ctrl_mem->start,
+ resource_size(clk_ctrl_mem));
+ if (!appbase) {
+ pr_err("clkctl_probe: appbase:err\n");
+ rc = -ENOMEM;
+ goto ioremap_fail;
+ }
+ return 0;
+
+ioremap_fail:
+ msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
+ return rc;
+}
+
+static int clkctl_remove(struct platform_device *pdev)
+{
+ if (clk_ctrl_mem)
+ iounmap(clk_ctrl_mem);
+
+ return 0;
+}
+
+static struct platform_driver clkctl_driver = {
+ .probe = clkctl_probe,
+ .remove = clkctl_remove,
+ .driver = {
+ .name = "msm_clk_ctl",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_clkctl_init_module(void)
+{
+ return platform_driver_register(&clkctl_driver);
+}
+
+static void __exit msm_clkctl_exit_module(void)
+{
+ platform_driver_unregister(&clkctl_driver);
+}
+
+module_init(msm_clkctl_init_module);
+module_exit(msm_clkctl_exit_module);
+MODULE_DESCRIPTION("CAM IO driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 0a1516b..6a9d7c4 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-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
@@ -69,6 +69,20 @@
}
}
+static int msm_isp_notify_VFE_BUF_FREE_EVT(struct v4l2_subdev *sd, void *arg)
+{
+ struct msm_vfe_cfg_cmd cfgcmd;
+ struct msm_camvfe_params vfe_params;
+ int rc;
+
+ cfgcmd.cmd_type = CMD_VFE_BUFFER_RELEASE;
+ cfgcmd.value = NULL;
+ vfe_params.vfe_cfg = &cfgcmd;
+ vfe_params.data = NULL;
+ rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
+ return 0;
+}
+
static int msm_isp_notify_VFE_BUF_EVT(struct v4l2_subdev *sd, void *arg)
{
int rc = -EINVAL;
@@ -89,6 +103,7 @@
switch (vdata->type) {
case VFE_MSG_V32_START:
case VFE_MSG_V32_START_RECORDING:
+ case VFE_MSG_V2X_PREVIEW:
D("%s Got V32_START_*: Getting ping addr id = %d",
__func__, vfe_id);
msm_mctl_reserve_free_buf(&pcam->mctl, vfe_id, &free_buf);
@@ -105,6 +120,7 @@
rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
break;
case VFE_MSG_V32_CAPTURE:
+ case VFE_MSG_V2X_CAPTURE:
pr_err("%s Got V32_CAPTURE: getting buffer for id = %d",
__func__, vfe_id);
msm_mctl_reserve_free_buf(&pcam->mctl, vfe_id, &free_buf);
@@ -161,6 +177,9 @@
if (notification == NOTIFY_VFE_BUF_EVT)
return msm_isp_notify_VFE_BUF_EVT(sd, arg);
+ if (notification == NOTIFY_VFE_BUF_FREE_EVT)
+ return msm_isp_notify_VFE_BUF_FREE_EVT(sd, arg);
+
isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), GFP_ATOMIC);
if (!isp_event) {
pr_err("%s Insufficient memory. return", __func__);
@@ -376,6 +395,19 @@
axi_data.region = ®ion[0];
return msm_isp_subdev_ioctl(sd, &cfgcmd,
&axi_data);
+ case CMD_STATS_AEC_AWB_ENABLE:
+ axi_data.bufnum1 =
+ msm_pmem_region_lookup(&sync->pmem_stats,
+ MSM_PMEM_AEC_AWB, ®ion[0],
+ NUM_STAT_OUTPUT_BUFFERS);
+ if (!axi_data.bufnum1) {
+ pr_err("%s %d: pmem region lookup error\n",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
+ axi_data.region = ®ion[0];
+ return msm_isp_subdev_ioctl(sd, &cfgcmd,
+ &axi_data);
case CMD_STATS_IHIST_ENABLE:
axi_data.bufnum1 =
msm_pmem_region_lookup(&sync->pmem_stats,
@@ -614,6 +646,8 @@
cfgcmd.cmd_type = CMD_STATS_RS_BUF_RELEASE;
else if (buf.type == STAT_CS)
cfgcmd.cmd_type = CMD_STATS_CS_BUF_RELEASE;
+ else if (buf.type == STAT_AEAW)
+ cfgcmd.cmd_type = CMD_STATS_BUF_RELEASE;
else {
pr_err("%s: invalid buf type %d\n",
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index e13dd62..e76b1d2 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -29,6 +29,7 @@
#include "msm.h"
#include "msm_csid.h"
+#include "msm_csic.h"
#include "msm_csiphy.h"
#include "msm_ispif.h"
#include "msm_sensor.h"
@@ -92,6 +93,14 @@
.colorspace = V4L2_COLORSPACE_JPEG,
},
{
+ .name = "NV21BAYER",
+ .depth = 8,
+ .bitsperpxl = 8,
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .pxlcode = V4L2_MBUS_FMT_SGRBG10_1X10, /* Bayer sensor */
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
+ {
.name = "YU12BAYER",
.depth = 8,
.bitsperpxl = 8,
@@ -107,6 +116,14 @@
.pxlcode = V4L2_MBUS_FMT_SBGGR10_1X10, /* Bayer sensor */
.colorspace = V4L2_COLORSPACE_JPEG,
},
+ {
+ .name = "RAWBAYER",
+ .depth = 10,
+ .bitsperpxl = 10,
+ .fourcc = V4L2_PIX_FMT_SBGGR10,
+ .pxlcode = V4L2_MBUS_FMT_SGRBG10_1X10, /* Bayer sensor */
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
};
@@ -225,6 +242,7 @@
case NOTIFY_VFE_MSG_OUT:
case NOTIFY_VFE_MSG_STATS:
case NOTIFY_VFE_BUF_EVT:
+ case NOTIFY_VFE_BUF_FREE_EVT:
if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_notify) {
rc = p_mctl->isp_sdev->isp_notify(
p_mctl->isp_sdev->sd, notification, arg);
@@ -248,6 +266,10 @@
rc = v4l2_subdev_call(p_mctl->csid_sdev,
core, ioctl, VIDIOC_MSM_CSID_CFG, arg);
break;
+ case NOTIFY_CSIC_CFG:
+ rc = v4l2_subdev_call(p_mctl->csic_sdev,
+ core, ioctl, VIDIOC_MSM_CSIC_CFG, arg);
+ break;
default:
break;
}
@@ -416,44 +438,70 @@
struct device *dev;
int rc = -ENODEV;
- /* register csiphy subdev */
- driver = driver_find(MSM_CSIPHY_DRV_NAME, &platform_bus_type);
- if (!driver)
- goto out;
+ struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(p_mctl->sensor_sdev);
+ struct msm_camera_sensor_info *sinfo =
+ (struct msm_camera_sensor_info *) s_ctrl->sensordata;
+ struct msm_camera_device_platform_data *pdata = sinfo->pdata;
- dev = driver_find_device(driver, NULL, (void *)core_index,
+ if (pdata->is_csiphy) {
+ /* register csiphy subdev */
+ driver = driver_find(MSM_CSIPHY_DRV_NAME, &platform_bus_type);
+ if (!driver)
+ goto out;
+
+ dev = driver_find_device(driver, NULL, (void *)core_index,
msm_mctl_subdev_match_core);
- if (!dev)
- goto out_put_driver;
+ if (!dev)
+ goto out_put_driver;
- p_mctl->csiphy_sdev = dev_get_drvdata(dev);
- put_driver(driver);
+ p_mctl->csiphy_sdev = dev_get_drvdata(dev);
+ put_driver(driver);
+ }
- /* register csid subdev */
- driver = driver_find(MSM_CSID_DRV_NAME, &platform_bus_type);
- if (!driver)
- goto out;
+ if (pdata->is_csic) {
+ /* register csic subdev */
+ driver = driver_find(MSM_CSIC_DRV_NAME, &platform_bus_type);
+ if (!driver)
+ goto out;
- dev = driver_find_device(driver, NULL, (void *)core_index,
+ dev = driver_find_device(driver, NULL, (void *)core_index,
msm_mctl_subdev_match_core);
- if (!dev)
- goto out_put_driver;
+ if (!dev)
+ goto out_put_driver;
- p_mctl->csid_sdev = dev_get_drvdata(dev);
- put_driver(driver);
+ p_mctl->csic_sdev = dev_get_drvdata(dev);
+ put_driver(driver);
+ }
- /* register ispif subdev */
- driver = driver_find(MSM_ISPIF_DRV_NAME, &platform_bus_type);
- if (!driver)
- goto out;
+ if (pdata->is_csid) {
+ /* register csid subdev */
+ driver = driver_find(MSM_CSID_DRV_NAME, &platform_bus_type);
+ if (!driver)
+ goto out;
- dev = driver_find_device(driver, NULL, 0,
+ dev = driver_find_device(driver, NULL, (void *)core_index,
msm_mctl_subdev_match_core);
- if (!dev)
- goto out_put_driver;
+ if (!dev)
+ goto out_put_driver;
- p_mctl->ispif_sdev = dev_get_drvdata(dev);
- put_driver(driver);
+ p_mctl->csid_sdev = dev_get_drvdata(dev);
+ put_driver(driver);
+ }
+
+ if (pdata->is_ispif) {
+ /* register ispif subdev */
+ driver = driver_find(MSM_ISPIF_DRV_NAME, &platform_bus_type);
+ if (!driver)
+ goto out;
+
+ dev = driver_find_device(driver, NULL, 0,
+ msm_mctl_subdev_match_core);
+ if (!dev)
+ goto out_put_driver;
+
+ p_mctl->ispif_sdev = dev_get_drvdata(dev);
+ put_driver(driver);
+ }
/* register vfe subdev */
driver = driver_find(MSM_VFE_DRV_NAME, &platform_bus_type);
@@ -468,18 +516,20 @@
p_mctl->isp_sdev->sd = dev_get_drvdata(dev);
put_driver(driver);
- /* register vfe subdev */
- driver = driver_find(MSM_VPE_DRV_NAME, &platform_bus_type);
- if (!driver)
- goto out;
+ if (pdata->is_vpe) {
+ /* register vfe subdev */
+ driver = driver_find(MSM_VPE_DRV_NAME, &platform_bus_type);
+ if (!driver)
+ goto out;
- dev = driver_find_device(driver, NULL, 0,
+ dev = driver_find_device(driver, NULL, 0,
msm_mctl_subdev_match_core);
- if (!dev)
- goto out_put_driver;
+ if (!dev)
+ goto out_put_driver;
- p_mctl->isp_sdev->sd_vpe = dev_get_drvdata(dev);
- put_driver(driver);
+ p_mctl->isp_sdev->sd_vpe = dev_get_drvdata(dev);
+ put_driver(driver);
+ }
rc = 0;
return rc;
@@ -522,20 +572,33 @@
goto msm_open_done;
}
- rc = v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
- VIDIOC_MSM_CSIPHY_INIT, NULL);
- if (rc < 0) {
- pr_err("%s: csiphy initialization failed %d\n",
+ if (camdev->is_csiphy) {
+ rc = v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
+ VIDIOC_MSM_CSIPHY_INIT, NULL);
+ if (rc < 0) {
+ pr_err("%s: csiphy initialization failed %d\n",
__func__, rc);
- goto msm_open_done;
+ goto msm_open_done;
+ }
}
- rc = v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
- VIDIOC_MSM_CSID_INIT, &csid_version);
- if (rc < 0) {
- pr_err("%s: csid initialization failed %d\n",
+ if (camdev->is_csid) {
+ rc = v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
+ VIDIOC_MSM_CSID_INIT, &csid_version);
+ if (rc < 0) {
+ pr_err("%s: csid initialization failed %d\n",
__func__, rc);
- goto msm_open_done;
+ goto msm_open_done;
+ }
+ }
+ if (camdev->is_csic) {
+ rc = v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
+ VIDIOC_MSM_CSIC_INIT, &csid_version);
+ if (rc < 0) {
+ pr_err("%s: csic initialization failed %d\n",
+ __func__, rc);
+ goto msm_open_done;
+ }
}
/* ISP first*/
@@ -548,12 +611,14 @@
goto msm_open_done;
}
- rc = v4l2_subdev_call(p_mctl->ispif_sdev, core, ioctl,
- VIDIOC_MSM_ISPIF_INIT, &csid_version);
- if (rc < 0) {
- pr_err("%s: ispif initialization failed %d\n",
+ if (camdev->is_ispif) {
+ rc = v4l2_subdev_call(p_mctl->ispif_sdev, core, ioctl,
+ VIDIOC_MSM_ISPIF_INIT, &csid_version);
+ if (rc < 0) {
+ pr_err("%s: ispif initialization failed %d\n",
__func__, rc);
- goto msm_open_done;
+ goto msm_open_done;
+ }
}
/* then sensor - move sub dev later*/
@@ -563,7 +628,6 @@
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);
@@ -573,12 +637,13 @@
goto msm_open_done;
}
- pm_qos_add_request(&p_mctl->pm_qos_req_list,
+ if (camdev->is_ispif) {
+ pm_qos_add_request(&p_mctl->pm_qos_req_list,
PM_QOS_CPU_DMA_LATENCY,
PM_QOS_DEFAULT_VALUE);
- pm_qos_update_request(&p_mctl->pm_qos_req_list,
+ pm_qos_update_request(&p_mctl->pm_qos_req_list,
MSM_V4L2_SWFI_LATENCY);
-
+ }
sync->apps_id = apps_id;
sync->opencnt++;
}
@@ -591,28 +656,44 @@
static int msm_mctl_release(struct msm_cam_media_controller *p_mctl)
{
int rc = 0;
- v4l2_subdev_call(p_mctl->ispif_sdev, core, ioctl,
- VIDIOC_MSM_ISPIF_RELEASE, NULL);
+ struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(p_mctl->sensor_sdev);
+ struct msm_camera_sensor_info *sinfo =
+ (struct msm_camera_sensor_info *) s_ctrl->sensordata;
+ struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+ if (camdev->is_ispif) {
+ v4l2_subdev_call(p_mctl->ispif_sdev, core, ioctl,
+ VIDIOC_MSM_ISPIF_RELEASE, NULL);
+ }
if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release)
p_mctl->isp_sdev->isp_release(&p_mctl->sync);
- v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
- VIDIOC_MSM_CSID_RELEASE, NULL);
+ if (camdev->is_csid) {
+ v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
+ VIDIOC_MSM_CSID_RELEASE, NULL);
+ }
- v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
- VIDIOC_MSM_CSIPHY_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);
-
- pm_qos_update_request(&p_mctl->pm_qos_req_list,
+ 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);
-
+ pm_qos_remove_request(&p_mctl->pm_qos_req_list);
+ }
wake_unlock(&p_mctl->sync.wake_lock);
return rc;
}
diff --git a/drivers/media/video/msm/msm_mem.c b/drivers/media/video/msm/msm_mem.c
index b631981..0ba1c0f 100644
--- a/drivers/media/video/msm/msm_mem.c
+++ b/drivers/media/video/msm/msm_mem.c
@@ -220,6 +220,7 @@
case MSM_PMEM_CS:
case MSM_PMEM_IHIST:
case MSM_PMEM_SKIN:
+ case MSM_PMEM_AEC_AWB:
rc = msm_pmem_table_add(ptype, pinfo, client);
break;
@@ -246,6 +247,7 @@
case MSM_PMEM_CS:
case MSM_PMEM_IHIST:
case MSM_PMEM_SKIN:
+ case MSM_PMEM_AEC_AWB:
hlist_for_each_entry_safe(region, node, n,
ptype, list) {
diff --git a/drivers/media/video/msm/msm_vfe31.c b/drivers/media/video/msm/msm_vfe31.c
index 2b3732c..f1d70aa 100644
--- a/drivers/media/video/msm/msm_vfe31.c
+++ b/drivers/media/video/msm/msm_vfe31.c
@@ -3892,6 +3892,7 @@
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->xbar_lock);
INIT_LIST_HEAD(&vfe31_ctrl->tasklet_q);
vfe31_init_free_buf_queue();
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
new file mode 100644
index 0000000..638c51d
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -0,0 +1,1353 @@
+/* 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/msm_adsp.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <linux/pm_qos_params.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/msm_isp.h>
+#include <mach/msm_adsp.h>
+#include <mach/clk.h>
+#include <mach/camera.h>
+#include "msm_vfe7x27a_v4l2.h"
+#include "msm.h"
+
+/* ADSP Messages */
+#define MSG_RESET_ACK 0
+#define MSG_STOP_ACK 1
+#define MSG_SNAPSHOT 2
+#define MSG_ILLEGAL_COMMAND 3
+#define MSG_START_ACK 4
+#define MSG_UPDATE_ACK 5
+#define MSG_OUTPUT1 6
+#define MSG_OUTPUT2 7
+#define MSG_STATS_AF 8
+#define MSG_STATS_WE 9
+#define MSG_STATS_HISTOGRAM 10
+#define MSG_EPOCH1 11
+#define MSG_EPOCH2 12
+#define MSG_VFE_ERROR 13
+#define MSG_SYNC_TIMER1_DONE 14
+#define MSG_SYNC_TIMER2_DONE 15
+#define MSG_ASYNC_TIMER1_DONE 16
+#define MSG_ASYNC_TIMER2_DONE 17
+#define MSG_CAPTURE_COMPLETE 18
+#define MSG_TABLE_CMD_ACK 19
+#define MSG_EXP_TIMEOUT_ACK 20
+#define MSG_SOF 21
+#define MSG_OUTPUT_T 22
+#define MSG_OUTPUT_S 23
+
+#define VFE_ADSP_EVENT 0xFFFF
+#define SNAPSHOT_MASK_MODE 0x00000001
+#define MSM_AXI_QOS_PREVIEW 122000
+#define MSM_AXI_QOS_SNAPSHOT 192000
+
+
+#define QDSP_CMDQUEUE 25
+#define QDSP_SCALEQUEUE 26
+#define QDSP_TABLEQUEUE 27
+
+/* ADSP Scler queue Cmd IDs */
+#define VFE_SCALE_OUTPUT1_CONFIG 0
+#define VFE_SCALE_OUTPUT2_CONFIG 1
+#define VFE_SCALE_MAX 0xFFFFFFFF
+
+/* ADSP table queue Cmd IDs */
+#define VFE_AXI_INPUT_CONFIG 0
+#define VFE_AXI_OUTPUT_CONFIG 1
+#define VFE_RGB_GAMMA_CONFIG 2
+#define VFE_Y_GAMMA_CONFIG 3
+#define VFE_ROLL_OFF_CONFIG 4
+#define VFE_DEMOSAICv3_BPC_CFG 6
+#define VFE_DEMOSAICv3_ABF_CFG 7
+#define VFE_DEMOSAICv3_CFG 8
+#define VFE_MAX 0xFFFFFFFF
+
+/* ADSP cfg queue cmd IDs */
+#define VFE_RESET 0
+#define VFE_START 1
+#define VFE_STOP 2
+#define VFE_UPDATE 3
+#define VFE_CAMIF_CONFIG 4
+#define VFE_ACTIVE_REGION_CONFIG 5
+#define VFE_DEMOSAIC_CONFIG 6
+#define VFE_INPUT_FORMAT_CONFIG 7
+#define VFE_OUTPUT_CLAMP_CONFIG 8
+#define VFE_CHROMA_SUBSAMPLE_CONFIG 9
+#define VFE_BLACK_LEVEL_CONFIG 10
+#define VFE_WHITE_BALANCE_CONFIG 11
+#define VFE_COLOR_PROCESSING_CONFIG 12
+#define VFE_ADAPTIVE_FILTER_CONFIG 13
+#define VFE_FRAME_SKIP_CONFIG 14
+#define VFE_FOV_CROP 15
+#define VFE_STATS_AUTOFOCUS_CONFIG 16
+#define VFE_STATS_WB_EXP_CONFIG 17
+#define VFE_STATS_HISTOGRAM_CONFIG 18
+#define VFE_OUTPUT1_ACK 19
+#define VFE_OUTPUT2_ACK 20
+#define VFE_STATS_AUTOFOCUS_ACK 21
+#define VFE_STATS_WB_EXP_ACK 22
+#define VFE_EPOCH1_ACK 23
+#define VFE_EPOCH2_ACK 24
+#define VFE_UPDATE_CAMIF_FRAME_CONFIG 25
+#define VFE_SYNC_TIMER1_CONFIG 26
+#define VFE_SYNC_TIMER2_CONFIG 27
+#define VFE_ASYNC_TIMER1_START 28
+#define VFE_ASYNC_TIMER2_START 29
+#define VFE_STATS_AUTOFOCUS_UPDATE 30
+#define VFE_STATS_WB_EXP_UPDATE 31
+#define VFE_ROLL_OFF_UPDATE 33
+#define VFE_DEMOSAICv3_BPC_UPDATE 34
+#define VFE_TESTGEN_START 35
+#define VFE_STATS_MA 0xFFFFFFFF
+
+struct msg_id_map msgs_map[] = {
+ {MSG_RESET_ACK, MSG_ID_RESET_ACK},
+ {MSG_STOP_ACK, MSG_ID_STOP_ACK},
+ {MSG_SNAPSHOT, MSG_ID_SNAPSHOT_DONE},
+ {MSG_ILLEGAL_COMMAND, VFE_MAX},
+ {MSG_START_ACK, MSG_ID_START_ACK},
+ {MSG_UPDATE_ACK, MSG_ID_UPDATE_ACK},
+ {MSG_OUTPUT1, VFE_MAX},
+ {MSG_OUTPUT2, VFE_MAX},
+ {MSG_STATS_AF, MSG_ID_STATS_AF},
+ {MSG_STATS_WE, MSG_ID_STATS_AWB_AEC},
+ {MSG_STATS_HISTOGRAM, MSG_ID_STATS_IHIST},
+ {MSG_EPOCH1, MSG_ID_EPOCH1},
+ {MSG_EPOCH2, MSG_ID_EPOCH2},
+ {MSG_VFE_ERROR, MSG_ID_CAMIF_ERROR},
+ {MSG_SYNC_TIMER1_DONE, MSG_ID_SYNC_TIMER1_DONE},
+ {MSG_SYNC_TIMER2_DONE, MSG_ID_SYNC_TIMER2_DONE},
+ {MSG_ASYNC_TIMER1_DONE, MSG_ID_ASYNC_TIMER1_DONE},
+ {MSG_ASYNC_TIMER2_DONE, MSG_ID_ASYNC_TIMER2_DONE},
+ {MSG_CAPTURE_COMPLETE, MSG_CAPTURE_COMPLETE},
+ {MSG_TABLE_CMD_ACK, MSG_TABLE_CMD_ACK},
+ {MSG_EXP_TIMEOUT_ACK, MSG_EXP_TIMEOUT_ACK},
+ {MSG_SOF, MSG_ID_SOF_ACK},
+ {MSG_OUTPUT_T, MSG_ID_OUTPUT_T},
+ {MSG_OUTPUT_S, MSG_ID_OUTPUT_S},
+};
+
+struct cmd_id_map cmds_map[] = {
+ {VFE_CMD_DUMMY_0, VFE_MAX, VFE_MAX},
+ {VFE_CMD_SET_CLK, VFE_MAX, VFE_MAX},
+ {VFE_CMD_RESET, VFE_RESET, QDSP_CMDQUEUE,
+ "VFE_CMD_RESET", "VFE_RESET"},
+ {VFE_CMD_START, VFE_START, QDSP_CMDQUEUE,
+ "VFE_CMD_START", "VFE_START"},
+ {VFE_CMD_TEST_GEN_START, VFE_TESTGEN_START, QDSP_CMDQUEUE,
+ "VFE_CMD_TEST_GEN_START", "VFE_TESTGEN_START"},
+ {VFE_CMD_OPERATION_CFG, VFE_MAX , VFE_MAX},
+ {VFE_CMD_AXI_OUT_CFG, VFE_AXI_OUTPUT_CONFIG, QDSP_TABLEQUEUE,
+ "VFE_CMD_AXI_OUT_CFG", "VFE_AXI_OUTPUT_CONFIG"},
+ {VFE_CMD_CAMIF_CFG, VFE_CAMIF_CONFIG, QDSP_CMDQUEUE,
+ "VFE_CMD_CAMIF_CFG", "VFE_CAMIF_CONFIG"},
+ {VFE_CMD_AXI_INPUT_CFG, VFE_AXI_INPUT_CONFIG, QDSP_TABLEQUEUE,
+ "VFE_CMD_AXI_INPUT_CFG", "VFE_AXI_INPUT_CONFIG"},
+ {VFE_CMD_BLACK_LEVEL_CFG, VFE_BLACK_LEVEL_CONFIG, QDSP_CMDQUEUE,
+ "VFE_CMD_BLACK_LEVEL_CFG", "VFE_BLACK_LEVEL_CONFIG"},
+ {VFE_CMD_MESH_ROLL_OFF_CFG, VFE_ROLL_OFF_CONFIG, QDSP_TABLEQUEUE,
+ "VFE_CMD_MESH_ROLL_OFF_CFG", "VFE_ROLL_OFF_CONFIG"},
+ {VFE_CMD_DEMUX_CFG, VFE_INPUT_FORMAT_CONFIG, QDSP_CMDQUEUE,
+ "VFE_CMD_DEMUX_CFG", "VFE_INPUT_FORMAT_CONFIG"},
+ {VFE_CMD_FOV_CFG, VFE_FOV_CROP, QDSP_CMDQUEUE,
+ "VFE_CMD_FOV_CFG", "VFE_FOV_CROP"},
+ {VFE_CMD_MAIN_SCALER_CFG, VFE_MAX, VFE_MAX},
+ {VFE_CMD_WB_CFG, VFE_WHITE_BALANCE_CONFIG, QDSP_CMDQUEUE,
+ "VFE_CMD_WB_CFG", "VFE_WHITE_BALANCE_CONFIG"},
+ {VFE_CMD_COLOR_COR_CFG, VFE_MAX, VFE_MAX},
+ {VFE_CMD_RGB_G_CFG, VFE_RGB_GAMMA_CONFIG, QDSP_TABLEQUEUE,
+ "VFE_CMD_RGB_G_CFG", "VFE_RGB_GAMMA_CONFIG"},
+ {VFE_CMD_LA_CFG, VFE_MAX, VFE_MAX},
+ {VFE_CMD_CHROMA_EN_CFG, VFE_MAX, VFE_MAX},
+ {VFE_CMD_CHROMA_SUP_CFG, VFE_MAX, VFE_MAX},
+ {VFE_CMD_MCE_CFG, VFE_MAX, VFE_MAX},
+ {VFE_CMD_SK_ENHAN_CFG, VFE_MAX, VFE_MAX},
+ {VFE_CMD_ASF_CFG, VFE_ADAPTIVE_FILTER_CONFIG, QDSP_CMDQUEUE,
+ "VFE_CMD_ASF_CFG", "VFE_ADAPTIVE_FILTER_CONFIG"},
+ {VFE_CMD_S2Y_CFG, VFE_MAX, VFE_MAX},
+ {VFE_CMD_S2CbCr_CFG, VFE_MAX, VFE_MAX},
+ {VFE_CMD_CHROMA_SUBS_CFG, VFE_CHROMA_SUBSAMPLE_CONFIG, QDSP_CMDQUEUE,
+ "VFE_CMD_CHROMA_SUBS_CFG", "VFE_CHROMA_SUBSAMPLE_CONFIG"},
+ {VFE_CMD_OUT_CLAMP_CFG, VFE_OUTPUT_CLAMP_CONFIG, QDSP_CMDQUEUE,
+ "VFE_CMD_OUT_CLAMP_CFG", "VFE_OUTPUT_CLAMP_CONFIG"},
+ {VFE_CMD_FRAME_SKIP_CFG, VFE_FRAME_SKIP_CONFIG, QDSP_CMDQUEUE,
+ "VFE_CMD_FRAME_SKIP_CFG", "VFE_FRAME_SKIP_CONFIG"},
+ {VFE_CMD_DUMMY_1, VFE_MAX, VFE_MAX},
+ {VFE_CMD_DUMMY_2, VFE_MAX, VFE_MAX},
+ {VFE_CMD_DUMMY_3, VFE_MAX, VFE_MAX},
+ {VFE_CMD_UPDATE, VFE_UPDATE, QDSP_CMDQUEUE,
+ "VFE_CMD_UPDATE", "VFE_UPDATE"},
+ {VFE_CMD_BL_LVL_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_DEMUX_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_FOV_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_MAIN_SCALER_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_WB_UPDATE, VFE_WHITE_BALANCE_CONFIG, QDSP_CMDQUEUE,
+ "VFE_CMD_WB_UPDATE", "VFE_WHITE_BALANCE_CONFIG"},
+ {VFE_CMD_COLOR_COR_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_RGB_G_UPDATE, VFE_RGB_GAMMA_CONFIG, QDSP_TABLEQUEUE,
+ "VFE_CMD_RGB_G_UPDATE", "VFE_RGB_GAMMA_CONFIG"},
+ {VFE_CMD_LA_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_CHROMA_EN_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_CHROMA_SUP_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_MCE_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_SK_ENHAN_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_S2CbCr_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_S2Y_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_ASF_UPDATE, VFE_ADAPTIVE_FILTER_CONFIG, QDSP_CMDQUEUE,
+ "VFE_CMD_ASF_UPDATE", "VFE_ADAPTIVE_FILTER_CONFIG"},
+ {VFE_CMD_FRAME_SKIP_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_CAMIF_FRAME_UPDATE, VFE_UPDATE_CAMIF_FRAME_CONFIG,
+ QDSP_CMDQUEUE, "VFE_CMD_CAMIF_FRAME_UPDATE",
+ "VFE_UPDATE_CAMIF_FRAME_CONFIG"},
+ {VFE_CMD_STATS_AF_UPDATE, VFE_STATS_AUTOFOCUS_UPDATE, QDSP_CMDQUEUE,
+ "VFE_CMD_STATS_AF_UPDATE", "VFE_STATS_AUTOFOCUS_UPDATE"},
+ {VFE_CMD_STATS_AE_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_AWB_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_RS_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_CS_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_SKIN_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_IHIST_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_DUMMY_4, VFE_MAX, VFE_MAX},
+ {VFE_CMD_EPOCH1_ACK, VFE_EPOCH1_ACK, QDSP_CMDQUEUE,
+ "VFE_CMD_EPOCH1_ACK", "VFE_EPOCH1_ACK"},
+ {VFE_CMD_EPOCH2_ACK, VFE_EPOCH2_ACK, QDSP_CMDQUEUE,
+ "VFE_CMD_EPOCH2_ACK", "VFE_EPOCH2_ACK"},
+ {VFE_CMD_START_RECORDING, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STOP_RECORDING, VFE_MAX , VFE_MAX},
+ {VFE_CMD_DUMMY_5, VFE_MAX, VFE_MAX},
+ {VFE_CMD_DUMMY_6, VFE_MAX, VFE_MAX},
+ {VFE_CMD_CAPTURE, VFE_START, QDSP_CMDQUEUE,
+ "VFE_CMD_CAPTURE", "VFE_START"},
+ {VFE_CMD_DUMMY_7, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STOP, VFE_STOP, QDSP_CMDQUEUE, "VFE_CMD_STOP", "VFE_STOP"},
+ {VFE_CMD_GET_HW_VERSION, VFE_MAX, VFE_MAX},
+ {VFE_CMD_GET_FRAME_SKIP_COUNTS, VFE_MAX, VFE_MAX},
+ {VFE_CMD_OUTPUT1_BUFFER_ENQ, VFE_MAX, VFE_MAX},
+ {VFE_CMD_OUTPUT2_BUFFER_ENQ, VFE_MAX, VFE_MAX},
+ {VFE_CMD_OUTPUT3_BUFFER_ENQ, VFE_MAX, VFE_MAX},
+ {VFE_CMD_JPEG_OUT_BUF_ENQ, VFE_MAX, VFE_MAX},
+ {VFE_CMD_RAW_OUT_BUF_ENQ, VFE_MAX, VFE_MAX},
+ {VFE_CMD_RAW_IN_BUF_ENQ, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_AF_ENQ, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_AE_ENQ, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_AWB_ENQ, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_RS_ENQ, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_CS_ENQ, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_SKIN_ENQ, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_IHIST_ENQ, VFE_MAX, VFE_MAX},
+ {VFE_CMD_DUMMY_8, VFE_MAX, VFE_MAX},
+ {VFE_CMD_JPEG_ENC_CFG, VFE_MAX, VFE_MAX},
+ {VFE_CMD_DUMMY_9, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_AF_START, VFE_STATS_AUTOFOCUS_CONFIG, QDSP_CMDQUEUE,
+ "VFE_CMD_STATS_AF_START", "VFE_STATS_AUTOFOCUS_CONFIG"},
+ {VFE_CMD_STATS_AF_STOP, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_AE_START, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_AE_STOP, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_AWB_START, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_AWB_STOP, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_RS_START, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_RS_STOP, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_CS_START, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_CS_STOP, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_SKIN_START, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_SKIN_STOP, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_IHIST_START, VFE_STATS_HISTOGRAM_CONFIG, QDSP_CMDQUEUE,
+ "VFE_CMD_STATS_IHIST_START", "VFE_STATS_HISTOGRAM_CONFIG"},
+ {VFE_CMD_STATS_IHIST_STOP, VFE_MAX, VFE_MAX},
+ {VFE_CMD_DUMMY_10, VFE_MAX, VFE_MAX},
+ {VFE_CMD_SYNC_TIMER_SETTING, VFE_MAX, VFE_MAX},
+ {VFE_CMD_ASYNC_TIMER_SETTING, VFE_MAX, VFE_MAX},
+ {VFE_CMD_LIVESHOT, VFE_MAX, VFE_MAX},
+ {VFE_CMD_LA_SETUP, VFE_MAX, VFE_MAX},
+ {VFE_CMD_LINEARIZATION_CFG, VFE_MAX, VFE_MAX},
+ {VFE_CMD_DEMOSAICV3, VFE_DEMOSAICv3_CFG, QDSP_TABLEQUEUE,
+ "VFE_CMD_DEMOSAICV3", "VFE_DEMOSAICv3_CFG"},
+ {VFE_CMD_DEMOSAICV3_ABCC_CFG, VFE_MAX, VFE_MAX},
+ {VFE_CMD_DEMOSAICV3_DBCC_CFG, VFE_MAX, VFE_MAX},
+ {VFE_CMD_DEMOSAICV3_DBPC_CFG, VFE_DEMOSAICv3_BPC_CFG, QDSP_TABLEQUEUE,
+ "VFE_CMD_DEMOSAICV3_DBPC_CFG", "VFE_DEMOSAICv3_BPC_CFG"},
+ {VFE_CMD_DEMOSAICV3_ABF_CFG, VFE_DEMOSAICv3_ABF_CFG, QDSP_TABLEQUEUE,
+ "VFE_CMD_DEMOSAICV3_ABF_CFG", "VFE_DEMOSAICv3_ABF_CFG"},
+ {VFE_CMD_DEMOSAICV3_ABCC_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_DEMOSAICV3_DBCC_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_DEMOSAICV3_DBPC_UPDATE, VFE_DEMOSAICv3_BPC_UPDATE,
+ QDSP_CMDQUEUE, "VFE_CMD_DEMOSAICV3_DBPC_UPDATE",
+ "VFE_DEMOSAICv3_BPC_UPDATE"},
+ {VFE_CMD_XBAR_CFG, VFE_MAX, VFE_MAX},
+ {VFE_CMD_MODULE_CFG, VFE_MAX, VFE_MAX},
+ {VFE_CMD_ZSL, VFE_MAX, VFE_MAX},
+ {VFE_CMD_LINEARIZATION_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_DEMOSAICV3_ABF_UPDATE, VFE_DEMOSAICv3_ABF_CFG,
+ QDSP_TABLEQUEUE, "VFE_CMD_DEMOSAICV3_ABF_UPDATE",
+ "VFE_DEMOSAICv3_ABF_CFG"},
+ {VFE_CMD_CLF_CFG, VFE_MAX, VFE_MAX},
+ {VFE_CMD_CLF_LUMA_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_CLF_CHROMA_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_PCA_ROLL_OFF_CFG, VFE_MAX, VFE_MAX},
+ {VFE_CMD_PCA_ROLL_OFF_UPDATE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_GET_REG_DUMP, VFE_MAX, VFE_MAX},
+ {VFE_CMD_GET_LINEARIZATON_TABLE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_GET_MESH_ROLLOFF_TABLE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_GET_PCA_ROLLOFF_TABLE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_GET_RGB_G_TABLE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_GET_LA_TABLE, VFE_MAX, VFE_MAX},
+ {VFE_CMD_DEMOSAICV3_UPDATE, VFE_DEMOSAICv3_CFG, QDSP_TABLEQUEUE,
+ "VFE_CMD_DEMOSAICV3_UPDATE", "VFE_DEMOSAICv3_CFG"},
+ {VFE_CMD_ACTIVE_REGION_CFG, VFE_ACTIVE_REGION_CONFIG, QDSP_CMDQUEUE,
+ "VFE_CMD_ACTIVE_REGION_CFG", "VFE_ACTIVE_REGION_CONFIG"},
+ {VFE_CMD_COLOR_PROCESSING_CONFIG, VFE_COLOR_PROCESSING_CONFIG,
+ QDSP_CMDQUEUE, "VFE_CMD_COLOR_PROCESSING_CONFIG",
+ "VFE_COLOR_PROCESSING_CONFIG"},
+ {VFE_CMD_STATS_WB_AEC_CONFIG, VFE_STATS_WB_EXP_CONFIG, QDSP_CMDQUEUE,
+ "VFE_CMD_STATS_WB_AEC_CONFIG", "VFE_STATS_WB_EXP_CONFIG"},
+ {VFE_CMD_STATS_WB_AEC_UPDATE, VFE_STATS_WB_EXP_UPDATE, QDSP_CMDQUEUE,
+ "VFE_CMD_STATS_WB_AEC_UPDATE", "VFE_STATS_WB_EXP_UPDATE"},
+ {VFE_CMD_Y_GAMMA_CONFIG, VFE_Y_GAMMA_CONFIG, QDSP_TABLEQUEUE,
+ "VFE_CMD_Y_GAMMA_CONFIG", "VFE_Y_GAMMA_CONFIG"},
+ {VFE_CMD_SCALE_OUTPUT1_CONFIG, VFE_SCALE_OUTPUT1_CONFIG,
+ QDSP_SCALEQUEUE, "VFE_CMD_SCALE_OUTPUT1_CONFIG",
+ "VFE_SCALE_OUTPUT1_CONFIG"},
+ {VFE_CMD_SCALE_OUTPUT2_CONFIG, VFE_SCALE_OUTPUT2_CONFIG,
+ QDSP_SCALEQUEUE, "VFE_CMD_SCALE_OUTPUT2_CONFIG",
+ "VFE_SCALE_OUTPUT2_CONFIG"},
+};
+
+
+static struct msm_adsp_module *qcam_mod;
+static struct msm_adsp_module *vfe_mod;
+static void *extdata;
+static uint32_t extlen;
+
+struct mutex vfe_lock;
+static void *vfe_syncdata;
+static uint8_t vfestopped;
+
+static struct stop_event stopevent;
+
+static uint32_t op_mode;
+static uint32_t raw_mode;
+static struct vfe2x_ctrl_type *vfe2x_ctrl;
+
+static void vfe2x_send_isp_msg(
+ struct vfe2x_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 = vfe2x_ctrl->vfeFrameId;
+ v4l2_subdev_notify(&vctrl->subdev,
+ NOTIFY_ISP_MSG_EVT,
+ (void *)&isp_msg_evt);
+}
+
+static void vfe_send_outmsg(struct v4l2_subdev *sd, uint8_t msgid,
+ uint32_t ch0_paddr, uint32_t ch1_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.frameCounter = vfe2x_ctrl->vfeFrameId;
+
+ v4l2_subdev_notify(&vfe2x_ctrl->subdev,
+ NOTIFY_VFE_MSG_OUT,
+ &msg);
+ return;
+}
+
+static void vfe_send_stats_msg(uint32_t buf_addr, uint32_t msg_id)
+{
+ struct isp_msg_stats msg_stats;
+
+ msg_stats.frameCounter = vfe2x_ctrl->vfeFrameId;
+ msg_stats.buffer = buf_addr;
+ msg_stats.id = msg_id;
+
+ v4l2_subdev_notify(&vfe2x_ctrl->subdev,
+ NOTIFY_VFE_MSG_STATS,
+ &msg_stats);
+}
+
+static void vfe_7x_ops(void *driver_data, unsigned id, size_t len,
+ void (*getevent)(void *ptr, size_t len))
+{
+ uint32_t evt_buf[3];
+ void *data;
+ struct buf_info *outch = NULL;
+ uint32_t y_phy, cbcr_phy;
+ struct table_cmd *table_pending = NULL;
+ unsigned long flags;
+ void *cmd_data = NULL;
+ unsigned char buf[256];
+ struct msm_free_buf *free_buf = NULL;
+ struct vfe_outputack fack;
+
+ CDBG("%s:id=%d\n", __func__, id);
+
+ if (id != VFE_ADSP_EVENT) {
+ data = kzalloc(len, GFP_KERNEL);
+ if (!data) {
+ pr_err("%s: rp: cannot allocate buffer\n", __func__);
+ return;
+ }
+ }
+ if (id == VFE_ADSP_EVENT) {
+ /* event */
+ getevent(evt_buf, sizeof(evt_buf));
+ CDBG("%s:event:msg_id=%d\n", __func__, id);
+ } else {
+ /* messages */
+ getevent(data, len);
+ CDBG("%s:messages:msg_id=%d\n", __func__, id);
+
+ switch (id) {
+ case MSG_SNAPSHOT:
+ msm_camio_set_perf_lvl(S_PREVIEW);
+ vfe_7x_ops(driver_data, MSG_OUTPUT_S, len, getevent);
+ if (!raw_mode)
+ vfe_7x_ops(driver_data, MSG_OUTPUT_T,
+ len, getevent);
+ vfe2x_send_isp_msg(vfe2x_ctrl, MSG_ID_SNAPSHOT_DONE);
+ return;
+ case MSG_OUTPUT_S:
+ outch = &vfe2x_ctrl->snap;
+ y_phy = outch->ping.ch_paddr[0];
+ cbcr_phy = outch->ping.ch_paddr[1];
+ CDBG("MSG_OUTPUT_S: %x %x\n",
+ (unsigned int)y_phy, (unsigned int)cbcr_phy);
+ vfe_send_outmsg(&vfe2x_ctrl->subdev, MSG_ID_OUTPUT_S,
+ y_phy, cbcr_phy);
+ break;
+ case MSG_OUTPUT_T:
+ outch = &vfe2x_ctrl->thumb;
+ y_phy = outch->ping.ch_paddr[0];
+ cbcr_phy = outch->ping.ch_paddr[1];
+ CDBG("MSG_OUTPUT_T: %x %x\n",
+ (unsigned int)y_phy, (unsigned int)cbcr_phy);
+ vfe_send_outmsg(&vfe2x_ctrl->subdev, MSG_ID_OUTPUT_T,
+ y_phy, cbcr_phy);
+ break;
+ case MSG_OUTPUT1:
+ case MSG_OUTPUT2:
+ if (op_mode & SNAPSHOT_MASK_MODE) {
+ kfree(data);
+ return;
+ } else {
+ free_buf = vfe2x_check_free_buffer(
+ VFE_MSG_OUTPUT_IRQ,
+ VFE_MSG_OUTPUT_P);
+ CDBG("free_buf = %x\n", (unsigned int) free_buf);
+ if (free_buf) {
+ fack.header = VFE_OUTPUT2_ACK;
+
+ fack.output2newybufferaddress =
+ (void *)(free_buf->ch_paddr[0]);
+
+ fack.output2newcbcrbufferaddress =
+ (void *)(free_buf->ch_paddr[1]);
+
+ cmd_data = &fack;
+ len = sizeof(fack);
+ msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
+ cmd_data, len);
+ } else {
+ fack.header = VFE_OUTPUT2_ACK;
+ fack.output2newybufferaddress =
+ (void *)
+ ((struct vfe_endframe *)data)->y_address;
+ fack.output2newcbcrbufferaddress =
+ (void *)
+ ((struct vfe_endframe *)data)->cbcr_address;
+ cmd_data = &fack;
+ len = sizeof(fack);
+ msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
+ cmd_data, len);
+ }
+ }
+ y_phy = ((struct vfe_endframe *)data)->y_address;
+ cbcr_phy = ((struct vfe_endframe *)data)->cbcr_address;
+
+
+ CDBG("vfe_7x_convert, y_phy = 0x%x, cbcr_phy = 0x%x\n",
+ y_phy, cbcr_phy);
+
+ memcpy(((struct vfe_frame_extra *)extdata),
+ &((struct vfe_endframe *)data)->extra,
+ sizeof(struct vfe_frame_extra));
+
+ vfe2x_ctrl->vfeFrameId =
+ ((struct vfe_frame_extra *)extdata)->frame_id;
+ vfe_send_outmsg(&vfe2x_ctrl->subdev,
+ MSG_ID_OUTPUT_P,
+ y_phy, cbcr_phy);
+ break;
+ case MSG_RESET_ACK:
+ case MSG_START_ACK:
+ case MSG_UPDATE_ACK:
+ case MSG_VFE_ERROR:
+ case MSG_SYNC_TIMER1_DONE:
+ case MSG_SYNC_TIMER2_DONE:
+ vfe2x_send_isp_msg(vfe2x_ctrl, msgs_map[id].isp_id);
+ if (id == MSG_START_ACK)
+ vfe2x_ctrl->vfe_started = 1;
+ break;
+ case MSG_SOF:
+ vfe2x_ctrl->vfeFrameId++;
+ if (vfe2x_ctrl->vfeFrameId == 0)
+ vfe2x_ctrl->vfeFrameId = 1; /* wrapped back */
+ vfe2x_send_isp_msg(vfe2x_ctrl, MSG_ID_SOF_ACK);
+ if (raw_mode)
+ vfe2x_send_isp_msg(vfe2x_ctrl,
+ MSG_ID_START_ACK);
+ break;
+ case MSG_STOP_ACK:
+ stopevent.state = 1;
+ vfe2x_ctrl->vfe_started = 0;
+ wake_up(&stopevent.wait);
+ vfe2x_send_isp_msg(vfe2x_ctrl, MSG_ID_STOP_ACK);
+ break;
+ case MSG_STATS_AF:
+ case MSG_STATS_WE:
+ vfe_send_stats_msg(*(uint32_t *)data,
+ msgs_map[id].isp_id);
+ break;
+ default:
+ vfe2x_send_isp_msg(vfe2x_ctrl, msgs_map[id].isp_id);
+ break;
+ }
+ }
+ if (MSG_TABLE_CMD_ACK == id) {
+ spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
+ if (list_empty(&vfe2x_ctrl->table_q)) {
+ if (vfe2x_ctrl->start_pending) {
+ CDBG("Send START\n");
+ cmd_data = buf;
+ *(uint32_t *)cmd_data = VFE_START;
+ memcpy(((char *)cmd_data) + 4,
+ &vfe2x_ctrl->start_cmd,
+ sizeof(vfe2x_ctrl->start_cmd));
+ /* Send Start cmd here */
+ len = sizeof(vfe2x_ctrl->start_cmd) + 4;
+ msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
+ cmd_data, len);
+ vfe2x_ctrl->start_pending = 0;
+ }
+ vfe2x_ctrl->tableack_pending = 0;
+ spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
+ return;
+ }
+ table_pending = list_first_entry(&vfe2x_ctrl->table_q,
+ struct table_cmd, list);
+ if (!table_pending) {
+ vfe2x_ctrl->tableack_pending = 0;
+ spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
+ return;
+ }
+ msm_adsp_write(vfe_mod, table_pending->queue,
+ table_pending->cmd, table_pending->size);
+ list_del(&table_pending->list);
+ kfree(table_pending->cmd);
+ vfe2x_ctrl->tableack_pending = 1;
+ spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
+ } else if (!vfe2x_ctrl->tableack_pending) {
+ if (!list_empty(&vfe2x_ctrl->table_q))
+ return;
+ }
+}
+
+static struct msm_adsp_ops vfe_7x_sync = {
+ .event = vfe_7x_ops,
+};
+
+static int vfe_7x_config_axi(int mode,
+ struct buf_info *ad, struct axiout *ao)
+{
+ unsigned long *bptr;
+ int cnt;
+ int rc = 0;
+
+
+ if (mode == OUTPUT_1) {
+ ao->output1buffer1_y_phy = ad->ping.ch_paddr[0];
+ ao->output1buffer1_cbcr_phy = ad->ping.ch_paddr[1];
+ ao->output1buffer2_y_phy = ad->pong.ch_paddr[0];
+ ao->output1buffer2_cbcr_phy = ad->pong.ch_paddr[1];
+ bptr = &ao->output1buffer3_y_phy;
+ for (cnt = 0; cnt < 6; cnt++) {
+ *bptr = ad->pong.ch_paddr[0];
+ bptr++;
+ *bptr = ad->pong.ch_paddr[1];
+ bptr++;
+ }
+ }
+
+ if (mode == OUTPUT_2) {
+ ao->output2buffer1_y_phy = ad->ping.ch_paddr[0];
+ ao->output2buffer1_cbcr_phy = ad->ping.ch_paddr[1];
+ ao->output2buffer2_y_phy = ad->pong.ch_paddr[0];
+ ao->output2buffer2_cbcr_phy = ad->pong.ch_paddr[1];
+ ao->output2buffer3_y_phy = ad->free_buf.ch_paddr[0];
+ ao->output2buffer3_cbcr_phy = ad->free_buf.ch_paddr[1];
+ bptr = &ao->output2buffer4_y_phy;
+ for (cnt = 0; cnt < 5; cnt++) {
+ *bptr = ad->pong.ch_paddr[0];
+ bptr++;
+ *bptr = ad->pong.ch_paddr[1];
+ bptr++;
+ }
+ }
+
+ if (mode == OUTPUT_1_AND_2) {
+ if (raw_mode) {
+ ao->output2buffer1_y_phy = ad->ping.ch_paddr[0];
+ ao->output2buffer1_cbcr_phy = ad->ping.ch_paddr[0];
+ ao->output2buffer2_y_phy = ad->pong.ch_paddr[0];
+ ao->output2buffer2_cbcr_phy = ad->pong.ch_paddr[0];
+ } else {
+ ao->output2buffer1_y_phy = ad->ping.ch_paddr[0];
+ ao->output2buffer1_cbcr_phy = ad->ping.ch_paddr[1];
+ ao->output2buffer2_y_phy = ad->pong.ch_paddr[0];
+ ao->output2buffer2_cbcr_phy = ad->pong.ch_paddr[1];
+ }
+ bptr = &ao->output2buffer3_y_phy;
+ for (cnt = 0; cnt < 6; cnt++) {
+ *bptr = ad->pong.ch_paddr[0];
+ bptr++;
+ *bptr = ad->pong.ch_paddr[0];
+ bptr++;
+ }
+ }
+
+ return rc;
+}
+
+static void vfe2x_subdev_notify(int id, int path)
+{
+ struct msm_vfe_resp *rp;
+ unsigned long flags = 0;
+ spin_lock_irqsave(&vfe2x_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");
+ return;
+ }
+ CDBG("vfe2x_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(&vfe2x_ctrl->subdev, NOTIFY_VFE_BUF_EVT, rp);
+ spin_unlock_irqrestore(&vfe2x_ctrl->sd_notify_lock, flags);
+}
+
+static struct msm_free_buf *vfe2x_check_free_buffer(int id, int path)
+{
+ struct buf_info *outch = NULL;
+
+ vfe2x_subdev_notify(id, path);
+ if (op_mode & SNAPSHOT_MASK_MODE) {
+ if (path == VFE_MSG_OUTPUT_S)
+ outch = &vfe2x_ctrl->snap;
+ else if (path == VFE_MSG_OUTPUT_T)
+ outch = &vfe2x_ctrl->thumb;
+ } else {
+ if (path == VFE_MSG_OUTPUT_P)
+ outch = &vfe2x_ctrl->prev;
+ }
+ if (outch->free_buf.ch_paddr[0])
+ return &outch->free_buf;
+
+ return NULL;
+}
+
+static int vfe2x_configure_pingpong_buffers(int id, int path)
+{
+ struct buf_info *outch = NULL;
+ int rc = 0;
+
+ vfe2x_subdev_notify(id, path);
+
+ CDBG("Opmode = %d\n", op_mode);
+ if (op_mode & SNAPSHOT_MASK_MODE) {
+ if (path == VFE_MSG_OUTPUT_S)
+ outch = &vfe2x_ctrl->snap;
+ else if (path == VFE_MSG_OUTPUT_T)
+ outch = &vfe2x_ctrl->thumb;
+ } else {
+ if (path == VFE_MSG_OUTPUT_P)
+ outch = &vfe2x_ctrl->prev;
+ }
+ 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);
+ } else {
+ pr_err("%s ping/pong addr is null!!", __func__);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+static struct buf_info *vfe2x_get_ch(int path)
+{
+ struct buf_info *ch = NULL;
+
+ CDBG("path = %d op_mode = %d\n", path, op_mode);
+ if (op_mode & SNAPSHOT_MASK_MODE) {
+ if (path == VFE_MSG_OUTPUT_T)
+ ch = &vfe2x_ctrl->thumb;
+ else if (path == VFE_MSG_OUTPUT_S)
+ ch = &vfe2x_ctrl->snap;
+ } else {
+ if (path == VFE_MSG_OUTPUT_P)
+ ch = &vfe2x_ctrl->prev;
+ }
+
+ BUG_ON(ch == NULL);
+ return ch;
+}
+
+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;
+ struct table_cmd *table_pending;
+ long rc = 0;
+ void *data = vfe_params->data;
+
+ struct msm_pmem_region *regptr;
+ unsigned char buf[256];
+
+ struct vfe_stats_ack sack;
+ struct axidata *axid;
+ uint32_t i;
+ uint32_t header = 0;
+ uint32_t queue = 0;
+ struct vfe_stats_we_cfg *scfg = NULL;
+ struct vfe_stats_af_cfg *sfcfg = NULL;
+
+ struct axiout *axio = NULL;
+ void *cmd_data = NULL;
+ void *cmd_data_alloc = NULL;
+ unsigned long flags;
+ struct msm_free_buf *free_buf = NULL;
+ struct vfe_outputack fack;
+
+ CDBG("msm_vfe_subdev_ioctl is called\n");
+ if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE &&
+ 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_VFE_BUFFER_RELEASE) {
+ if (copy_from_user(&vfecmd,
+ (void __user *)(cmd->value),
+ sizeof(vfecmd))) {
+ pr_err("copy_from_user in msm_vfe_subdev_ioctl fail\n");
+ return -EFAULT;
+ }
+ }
+
+ switch (cmd->cmd_type) {
+ case CMD_VFE_BUFFER_RELEASE: {
+ if (!(vfe2x_ctrl->vfe_started) || op_mode == 1)
+ return 0;
+ if (op_mode & SNAPSHOT_MASK_MODE) {
+ free_buf = vfe2x_check_free_buffer(
+ VFE_MSG_OUTPUT_IRQ,
+ VFE_MSG_OUTPUT_T);
+ } else {
+ free_buf = vfe2x_check_free_buffer(
+ VFE_MSG_OUTPUT_IRQ,
+ VFE_MSG_OUTPUT_P);
+ if (free_buf) {
+ fack.header = VFE_OUTPUT2_ACK;
+
+ fack.output2newybufferaddress =
+ (void *)(free_buf->ch_paddr[0]);
+
+ fack.output2newcbcrbufferaddress =
+ (void *)(free_buf->ch_paddr[1]);
+
+ cmd_data = &fack;
+ vfecmd.length = sizeof(fack) - 4;
+ queue = QDSP_CMDQUEUE;
+ }
+ }
+ }
+ break;
+ case CMD_CONFIG_PING_ADDR: {
+ int path = *((int *)cmd->value);
+ struct buf_info *outch = vfe2x_get_ch(path);
+ outch->ping = *((struct msm_free_buf *)data);
+ }
+ return 0;
+ case CMD_CONFIG_PONG_ADDR: {
+ int path = *((int *)cmd->value);
+ struct buf_info *outch = vfe2x_get_ch(path);
+ outch->pong = *((struct msm_free_buf *)data);
+ }
+ return 0;
+
+ case CMD_CONFIG_FREE_BUF_ADDR: {
+ int path = *((int *)cmd->value);
+ struct buf_info *outch = vfe2x_get_ch(path);
+ outch->free_buf = *((struct msm_free_buf *)data);
+ }
+ return 0;
+
+ case CMD_STATS_AEC_AWB_ENABLE:
+ case CMD_STATS_AXI_CFG: {
+ axid = data;
+ if (!axid) {
+ rc = -EFAULT;
+ goto config_failure;
+ }
+
+ scfg =
+ kmalloc(sizeof(struct vfe_stats_we_cfg),
+ GFP_ATOMIC);
+ if (!scfg) {
+ rc = -ENOMEM;
+ goto config_failure;
+ }
+
+ if (copy_from_user((char *)scfg + 4,
+ (void __user *)(vfecmd.value),
+ vfecmd.length)) {
+
+ rc = -EFAULT;
+ goto config_done;
+ }
+
+ CDBG("STATS_ENABLE: bufnum = %d, enabling = %d\n",
+ axid->bufnum1, scfg->wb_expstatsenable);
+
+ header = cmds_map[vfecmd.id].vfe_id;
+ queue = cmds_map[vfecmd.id].queue;
+ if (header == -1 && queue == -1) {
+ rc = -EFAULT;
+ goto config_failure;
+ }
+ *(uint32_t *)scfg = header;
+ if (axid->bufnum1 > 0) {
+ regptr = axid->region;
+
+ for (i = 0; i < axid->bufnum1; i++) {
+
+ CDBG("STATS_ENABLE, phy = 0x%lx\n",
+ regptr->paddr);
+
+ scfg->wb_expstatoutputbuffer[i] =
+ (void *)regptr->paddr;
+ regptr++;
+ }
+
+ cmd_data = scfg;
+
+ } else {
+ rc = -EINVAL;
+ goto config_done;
+ }
+ }
+ break;
+ case CMD_STATS_AF_ENABLE:
+ case CMD_STATS_AF_AXI_CFG: {
+ axid = data;
+ if (!axid) {
+ rc = -EFAULT;
+ goto config_failure;
+ }
+
+ sfcfg =
+ kmalloc(sizeof(struct vfe_stats_af_cfg),
+ GFP_ATOMIC);
+
+ if (!sfcfg) {
+ rc = -ENOMEM;
+ goto config_failure;
+ }
+
+ if (copy_from_user((char *)sfcfg + 4,
+ (void __user *)(vfecmd.value),
+ vfecmd.length)) {
+
+ rc = -EFAULT;
+ goto config_done;
+ }
+
+ CDBG("AF_ENABLE: bufnum = %d, enabling = %d\n",
+ axid->bufnum1, sfcfg->af_enable);
+
+ header = cmds_map[vfecmd.id].vfe_id;
+ queue = cmds_map[vfecmd.id].queue;
+ if (header == -1 && queue == -1) {
+ rc = -EFAULT;
+ goto config_failure;
+ }
+ *(uint32_t *)sfcfg = header;
+ if (axid->bufnum1 > 0) {
+ regptr = &axid->region[0];
+
+ for (i = 0; i < axid->bufnum1; i++) {
+
+ CDBG("STATS_ENABLE, phy = 0x%lx\n",
+ regptr->paddr);
+
+ sfcfg->af_outbuf[i] =
+ (void *)regptr->paddr;
+
+ regptr++;
+ }
+
+ cmd_data = sfcfg;
+
+ } else {
+ rc = -EINVAL;
+ goto config_done;
+ }
+ }
+ break;
+ case CMD_SNAP_BUF_RELEASE:
+ break;
+ case CMD_STATS_BUF_RELEASE: {
+ CDBG("vfe_7x_config: CMD_STATS_BUF_RELEASE\n");
+ if (!data) {
+ rc = -EFAULT;
+ goto config_failure;
+ }
+
+ sack.header = VFE_STATS_WB_EXP_ACK;
+ sack.bufaddr = (void *)*(uint32_t *)data;
+
+ queue = QDSP_CMDQUEUE;
+ vfecmd.length = sizeof(struct vfe_stats_ack) - 4;
+ cmd_data = &sack;
+ }
+ break;
+ case CMD_STATS_AF_BUF_RELEASE: {
+ CDBG("vfe_7x_config: CMD_STATS_AF_BUF_RELEASE\n");
+ if (!data) {
+ rc = -EFAULT;
+ goto config_failure;
+ }
+
+ sack.header = VFE_STATS_AUTOFOCUS_ACK;
+ sack.bufaddr = (void *)*(uint32_t *)data;
+
+ queue = QDSP_CMDQUEUE;
+ vfecmd.length = sizeof(struct vfe_stats_ack) - 4;
+ cmd_data = &sack;
+ }
+ break;
+ case CMD_GENERAL:
+ case CMD_STATS_DISABLE: {
+ CDBG("CMD_GENERAL:%d %d\n", vfecmd.id, vfecmd.length);
+ if (vfecmd.id == VFE_CMD_OPERATION_CFG) {
+ if (copy_from_user(&vfe2x_ctrl->start_cmd,
+ (void __user *)(vfecmd.value),
+ vfecmd.length))
+ rc = -EFAULT;
+ op_mode = vfe2x_ctrl->start_cmd.mode_of_operation;
+ return rc;
+ }
+ if (vfecmd.length > 256 - 4) {
+ cmd_data_alloc =
+ cmd_data = kmalloc(vfecmd.length + 4, GFP_ATOMIC);
+ if (!cmd_data) {
+ rc = -ENOMEM;
+ goto config_failure;
+ }
+ } else
+ cmd_data = buf;
+
+ if (copy_from_user(((char *)cmd_data) + 4,
+ (void __user *)(vfecmd.value),
+ vfecmd.length)) {
+
+ rc = -EFAULT;
+ goto config_done;
+ }
+ header = cmds_map[vfecmd.id].vfe_id;
+ queue = cmds_map[vfecmd.id].queue;
+ if (header == -1 && queue == -1) {
+ rc = -EFAULT;
+ goto config_done;
+ }
+ CDBG("%s %s\n", cmds_map[vfecmd.id].isp_id_name,
+ cmds_map[vfecmd.id].vfe_id_name);
+ *(uint32_t *)cmd_data = header;
+ if (queue == QDSP_CMDQUEUE) {
+ switch (vfecmd.id) {
+ case VFE_CMD_RESET:
+ msm_adsp_enable(qcam_mod);
+ msm_adsp_enable(vfe_mod);
+ msm_camio_vfe_blk_reset();
+ vfestopped = 0;
+ break;
+ case VFE_CMD_START:
+ case VFE_CMD_CAPTURE:
+ spin_lock_irqsave(&vfe2x_ctrl->table_lock,
+ flags);
+ if (!list_empty(&vfe2x_ctrl->table_q)) {
+ vfe2x_ctrl->start_pending = 1;
+ spin_unlock_irqrestore(
+ &vfe2x_ctrl->table_lock,
+ flags);
+ return 0;
+ }
+ spin_unlock_irqrestore(&vfe2x_ctrl->table_lock,
+ flags);
+ vfecmd.length = sizeof(vfe2x_ctrl->start_cmd);
+ memcpy(((char *)cmd_data) + 4,
+ &vfe2x_ctrl->start_cmd,
+ sizeof(vfe2x_ctrl->start_cmd));
+ if (op_mode & SNAPSHOT_MASK_MODE)
+ msm_camio_set_perf_lvl(S_CAPTURE);
+ else
+ msm_camio_set_perf_lvl(S_PREVIEW);
+ vfestopped = 0;
+ break;
+ case VFE_CMD_STOP:
+ vfestopped = 1;
+ vfe2x_ctrl->vfe_started = 0;
+ goto config_send;
+
+ default:
+ break;
+ }
+ } /* QDSP_CMDQUEUE */
+ }
+ break;
+ case CMD_AXI_CFG_PREVIEW: {
+ CDBG("CMD_AXI_CFG_PREVIEW\n");
+ raw_mode = 0;
+ axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
+ if (!axio) {
+ pr_err("NULL axio\n");
+ rc = -ENOMEM;
+ goto config_failure;
+ }
+
+ if (copy_from_user((char *)axio + 4,
+ (void __user *)(vfecmd.value),
+ sizeof(struct axiout))) {
+ pr_err("copy_from_user failed\n");
+ rc = -EFAULT;
+ goto config_done;
+ }
+ rc = vfe2x_configure_pingpong_buffers(VFE_MSG_V2X_PREVIEW,
+ VFE_MSG_OUTPUT_P);
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers"
+ " for preview", __func__);
+ rc = -EINVAL;
+ goto config_done;
+ }
+
+ free_buf = vfe2x_check_free_buffer(
+ VFE_MSG_OUTPUT_IRQ,
+ VFE_MSG_OUTPUT_P);
+ header = cmds_map[vfecmd.id].vfe_id;
+ queue = cmds_map[vfecmd.id].queue;
+ if (header == -1 && queue == -1) {
+ rc = -EFAULT;
+ goto config_done;
+ }
+ *(uint32_t *)axio = header;
+ vfe_7x_config_axi(OUTPUT_2, &vfe2x_ctrl->prev, axio);
+ cmd_data = axio;
+ }
+ break;
+ case CMD_RAW_PICT_AXI_CFG: {
+ CDBG("CMD_RAW_PICT_AXI_CFG:%d\n", op_mode);
+ raw_mode = 1;
+ axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ goto config_failure;
+ }
+
+ if (copy_from_user((char *)axio + 4,
+ (void __user *)(vfecmd.value),
+ sizeof(struct axiout))) {
+ rc = -EFAULT;
+ goto config_done;
+ }
+ header = cmds_map[vfecmd.id].vfe_id;
+ queue = cmds_map[vfecmd.id].queue;
+ rc = vfe2x_configure_pingpong_buffers(VFE_MSG_V2X_CAPTURE,
+ VFE_MSG_OUTPUT_S);
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers"
+ " for preview", __func__);
+ rc = -EINVAL;
+ goto config_done;
+ }
+ if (header == -1 && queue == -1) {
+ rc = -EFAULT;
+ goto config_done;
+ }
+ *(uint32_t *)axio = header;
+ vfe_7x_config_axi(OUTPUT_1_AND_2, &vfe2x_ctrl->snap, axio);
+ cmd_data = axio;
+ }
+ break;
+ case CMD_AXI_CFG_SNAP: {
+ raw_mode = 0;
+ CDBG("CMD_AXI_CFG_SNAP :%d\n", op_mode);
+ axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ goto config_failure;
+ }
+
+ if (copy_from_user((char *)axio + 4,
+ (void __user *)(vfecmd.value),
+ sizeof(struct axiout))) {
+ rc = -EFAULT;
+ goto config_done;
+ }
+ header = cmds_map[vfecmd.id].vfe_id;
+ queue = cmds_map[vfecmd.id].queue;
+ rc = vfe2x_configure_pingpong_buffers(VFE_MSG_V2X_CAPTURE,
+ VFE_MSG_OUTPUT_S);
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers"
+ " for preview", __func__);
+ rc = -EINVAL;
+ goto config_done;
+ }
+ if (header == -1 && queue == -1) {
+ rc = -EFAULT;
+ goto config_done;
+ }
+ *(uint32_t *)axio = header;
+ vfe_7x_config_axi(OUTPUT_1_AND_2, &vfe2x_ctrl->snap, axio);
+ rc = vfe2x_configure_pingpong_buffers(VFE_MSG_V2X_CAPTURE,
+ VFE_MSG_OUTPUT_T);
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers"
+ " for preview", __func__);
+ rc = -EINVAL;
+ goto config_done;
+ }
+ vfe_7x_config_axi(OUTPUT_1, &vfe2x_ctrl->thumb, axio);
+ cmd_data = axio;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (vfestopped)
+ goto config_done;
+
+config_send:
+ CDBG("send adsp command = %d\n", *(uint32_t *)cmd_data);
+ if (queue == QDSP_TABLEQUEUE &&
+ vfe2x_ctrl->tableack_pending) {
+ table_pending = kzalloc(sizeof(struct table_cmd), GFP_ATOMIC);
+ if (!table_pending) {
+ rc = -ENOMEM;
+ goto config_done;
+ }
+ table_pending->cmd = kzalloc(vfecmd.length + 4, GFP_ATOMIC);
+ if (!table_pending->cmd) {
+ kfree(table_pending);
+ rc = -ENOMEM;
+ goto config_done;
+ }
+ memcpy(table_pending->cmd, cmd_data, vfecmd.length + 4);
+ table_pending->queue = queue;
+ table_pending->size = vfecmd.length + 4;
+ spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
+ list_add_tail(&table_pending->list, &vfe2x_ctrl->table_q);
+ spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
+ } else {
+ if (queue == QDSP_TABLEQUEUE) {
+ spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
+ rc = msm_adsp_write(vfe_mod, queue,
+ cmd_data, vfecmd.length + 4);
+ vfe2x_ctrl->tableack_pending = 1;
+ spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
+ } else {
+ if (*(uint32_t *)cmd_data == VFE_OUTPUT2_ACK) {
+ uint32_t *ptr = cmd_data;
+ CDBG("%x %x %x\n", ptr[0], ptr[1], ptr[2]);
+ }
+ rc = msm_adsp_write(vfe_mod, queue,
+ cmd_data, vfecmd.length + 4);
+ CDBG("%x\n", vfecmd.length + 4);
+ }
+ }
+
+config_done:
+ kfree(cmd_data_alloc);
+
+config_failure:
+ kfree(scfg);
+ kfree(axio);
+ return rc;
+}
+
+static struct msm_cam_clk_info vfe2x_clk_info[] = {
+ {"vfe_clk", 192000000},
+};
+
+int msm_vfe_subdev_init(struct v4l2_subdev *sd, void *data,
+ struct platform_device *pdev)
+{
+ int rc = 0;
+ v4l2_set_subdev_hostdata(sd, data);
+ vfe_syncdata = data;
+
+ spin_lock_init(&vfe2x_ctrl->sd_notify_lock);
+ spin_lock_init(&vfe2x_ctrl->table_lock);
+ spin_lock_init(&vfe2x_ctrl->vfe_msg_lock);
+ init_waitqueue_head(&stopevent.wait);
+ INIT_LIST_HEAD(&vfe2x_ctrl->table_q);
+ INIT_LIST_HEAD(&vfe2x_ctrl->vfe_msg_q);
+ stopevent.timeout = 200;
+ stopevent.state = 0;
+ vfe2x_ctrl->vfe_started = 0;
+
+
+ CDBG("msm_cam_clk_enable: enable vfe_clk\n");
+ rc = msm_cam_clk_enable(&vfe2x_ctrl->pdev->dev, vfe2x_clk_info,
+ vfe2x_ctrl->vfe_clk, ARRAY_SIZE(vfe2x_clk_info), 1);
+ if (rc < 0)
+ return rc;
+
+ msm_camio_set_perf_lvl(S_INIT);
+
+ /* TODO : check is it required */
+ extlen = sizeof(struct vfe_frame_extra);
+
+ extdata = kmalloc(extlen, GFP_ATOMIC);
+ if (!extdata) {
+ rc = -ENOMEM;
+ goto init_fail;
+ }
+
+ rc = msm_adsp_get("QCAMTASK", &qcam_mod, &vfe_7x_sync, NULL);
+ if (rc) {
+ rc = -EBUSY;
+ goto get_qcam_fail;
+ }
+
+ rc = msm_adsp_get("VFETASK", &vfe_mod, &vfe_7x_sync, NULL);
+ if (rc) {
+ rc = -EBUSY;
+ goto get_vfe_fail;
+ }
+ return 0;
+
+get_vfe_fail:
+ msm_adsp_put(qcam_mod);
+get_qcam_fail:
+ kfree(extdata);
+init_fail:
+ extlen = 0;
+ return rc;
+}
+
+int msm_vpe_subdev_init(struct v4l2_subdev *sd, void *data,
+ struct platform_device *pdev)
+{
+ return 0;
+}
+
+void msm_vpe_subdev_release(struct platform_device *pdev)
+{
+ return;
+}
+
+void msm_vfe_subdev_release(struct platform_device *pdev)
+{
+ msm_cam_clk_enable(&vfe2x_ctrl->pdev->dev, vfe2x_clk_info,
+ vfe2x_ctrl->vfe_clk, ARRAY_SIZE(vfe2x_clk_info), 0);
+ vfe_syncdata = NULL;
+
+ msm_adsp_disable(qcam_mod);
+ msm_adsp_disable(vfe_mod);
+
+ msm_adsp_put(qcam_mod);
+ msm_adsp_put(vfe_mod);
+
+ kfree(extdata);
+ msm_camio_set_perf_lvl(S_EXIT);
+ return;
+}
+
+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,
+};
+
+static int __devinit vfe2x_probe(struct platform_device *pdev)
+{
+ CDBG("%s: device id = %d\n", __func__, pdev->id);
+ vfe2x_ctrl = kzalloc(sizeof(struct vfe2x_ctrl_type), GFP_KERNEL);
+ if (!vfe2x_ctrl) {
+ pr_err("%s: no enough memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ v4l2_subdev_init(&vfe2x_ctrl->subdev, &msm_vfe_subdev_ops);
+ snprintf(vfe2x_ctrl->subdev.name,
+ sizeof(vfe2x_ctrl->subdev.name), "vfe2.x");
+ v4l2_set_subdevdata(&vfe2x_ctrl->subdev, vfe2x_ctrl);
+ platform_set_drvdata(pdev, &vfe2x_ctrl->subdev);
+
+ vfe2x_ctrl->pdev = pdev;
+ return 0;
+}
+
+static struct platform_driver vfe2x_driver = {
+ .probe = vfe2x_probe,
+ .driver = {
+ .name = MSM_VFE_DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_vfe2x_init_module(void)
+{
+ return platform_driver_register(&vfe2x_driver);
+}
+
+static void __exit msm_vfe2x_exit_module(void)
+{
+ platform_driver_unregister(&vfe2x_driver);
+}
+
+module_init(msm_vfe2x_init_module);
+module_exit(msm_vfe2x_exit_module);
+MODULE_DESCRIPTION("VFE 2.x driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.h b/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
new file mode 100644
index 0000000..0f7fb60
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
@@ -0,0 +1,385 @@
+/* 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_VFE7X_H__
+#define __MSM_VFE7X_H__
+#include <media/msm_camera.h>
+#include <mach/camera.h>
+#include <linux/list.h>
+#include "msm.h"
+
+struct cmd_id_map {
+ uint32_t isp_id;
+ uint32_t vfe_id;
+ uint32_t queue;
+ char isp_id_name[64];
+ char vfe_id_name[64];
+} __packed;
+
+struct msg_id_map {
+ uint32_t vfe_id;
+ uint32_t isp_id;
+} __packed;
+
+struct table_cmd {
+ struct list_head list;
+ void *cmd;
+ int size;
+ int queue;
+} __packed;
+
+struct vfe_msg {
+ struct list_head list;
+ void *cmd;
+ int len;
+ int id;
+} __packed;
+
+struct buf_info {
+ /* Buffer */
+ struct msm_free_buf ping;
+ struct msm_free_buf pong;
+ struct msm_free_buf free_buf;
+} __packed;
+
+struct vfe_cmd_start {
+ uint32_t input_source:1;
+ uint32_t mode_of_operation:1;
+ uint32_t snap_number:4;
+ uint32_t /* reserved */ : 26;
+
+ /* Image Pipeline Modules */
+ uint32_t blacklevel_correction_enable:1;
+ uint32_t lens_rolloff_correction_enable:1;
+ uint32_t white_balance_enable:1;
+ uint32_t rgb_gamma_enable:1;
+ uint32_t luma_noise_reductionpath_enable:1;
+ uint32_t adaptive_spatialfilter_enable:1;
+ uint32_t chroma_subsample_enable:1;
+ uint32_t /* reserved */ : 25;
+
+ /* The dimension fed to the statistics module */
+ uint32_t last_pixel:12;
+ uint32_t /* reserved */ : 4;
+ uint32_t last_line:12;
+ uint32_t /* reserved */ : 4;
+} __packed;
+
+struct vfe2x_ctrl_type {
+ struct buf_info prev;
+ struct buf_info snap;
+ struct buf_info raw;
+ struct buf_info thumb;
+
+ spinlock_t table_lock;
+ struct list_head table_q;
+ uint32_t tableack_pending;
+ uint32_t vfeFrameId;
+
+ spinlock_t vfe_msg_lock;
+ struct list_head vfe_msg_q;
+
+ struct vfe_cmd_start start_cmd;
+ uint32_t start_pending;
+ uint32_t vfe_started;
+
+ /* v4l2 subdev */
+ struct v4l2_subdev subdev;
+ struct platform_device *pdev;
+ struct clk *vfe_clk[3];
+ spinlock_t sd_notify_lock;
+} __packed;
+
+struct vfe_frame_extra {
+ uint32_t bl_evencol:23;
+ uint32_t rvd1:9;
+ uint32_t bl_oddcol:23;
+ uint32_t rvd2:9;
+
+ uint32_t d_dbpc_stats_hot:16;
+ uint32_t d_dbpc_stats_cold:16;
+
+ uint32_t d_dbpc_stats_0_hot:10;
+ uint32_t rvd3:6;
+ uint32_t d_dbpc_stats_0_cold:10;
+ uint32_t rvd4:6;
+ uint32_t d_dbpc_stats_1_hot:10;
+ uint32_t rvd5:6;
+ uint32_t d_dbpc_stats_1_cold:10;
+ uint32_t rvd6:6;
+
+ uint32_t asf_max_edge;
+
+ uint32_t e_y_wm_pm_stats_0:21;
+ uint32_t rvd7:11;
+ uint32_t e_y_wm_pm_stats_1_bl:8;
+ uint32_t rvd8:8;
+ uint32_t e_y_wm_pm_stats_1_nl:12;
+ uint32_t rvd9:4;
+
+ uint32_t e_cbcr_wm_pm_stats_0:21;
+ uint32_t rvd10:11;
+ uint32_t e_cbcr_wm_pm_stats_1_bl:8;
+ uint32_t rvd11:8;
+ uint32_t e_cbcr_wm_pm_stats_1_nl:12;
+ uint32_t rvd12:4;
+
+ uint32_t v_y_wm_pm_stats_0:21;
+ uint32_t rvd13:11;
+ uint32_t v_y_wm_pm_stats_1_bl:8;
+ uint32_t rvd14:8;
+ uint32_t v_y_wm_pm_stats_1_nl:12;
+ uint32_t rvd15:4;
+
+ uint32_t v_cbcr_wm_pm_stats_0:21;
+ uint32_t rvd16:11;
+ uint32_t v_cbcr_wm_pm_stats_1_bl:8;
+ uint32_t rvd17:8;
+ uint32_t v_cbcr_wm_pm_stats_1_nl:12;
+ uint32_t rvd18:4;
+
+ uint32_t frame_id;
+} __packed;
+
+struct vfe_endframe {
+ uint32_t y_address;
+ uint32_t cbcr_address;
+
+ struct vfe_frame_extra extra;
+} __packed;
+
+struct vfe_outputack {
+ uint32_t header;
+ void *output2newybufferaddress;
+ void *output2newcbcrbufferaddress;
+} __packed;
+
+struct vfe_stats_ack {
+ uint32_t header;
+ /* MUST BE 64 bit ALIGNED */
+ void *bufaddr;
+} __packed;
+
+/* AXI Output Config Command sent to DSP */
+struct axiout {
+ uint32_t cmdheader:32;
+ int outputmode:3;
+ uint8_t format:2;
+ uint32_t /* reserved */ : 27;
+
+ /* AXI Output 1 Y Configuration, Part 1 */
+ uint32_t out1yimageheight:12;
+ uint32_t /* reserved */ : 4;
+ uint32_t out1yimagewidthin64bitwords:10;
+ uint32_t /* reserved */ : 6;
+
+ /* AXI Output 1 Y Configuration, Part 2 */
+ uint8_t out1yburstlen:2;
+ uint32_t out1ynumrows:12;
+ uint32_t out1yrowincin64bitincs:12;
+ uint32_t /* reserved */ : 6;
+
+ /* AXI Output 1 CbCr Configuration, Part 1 */
+ uint32_t out1cbcrimageheight:12;
+ uint32_t /* reserved */ : 4;
+ uint32_t out1cbcrimagewidthin64bitwords:10;
+ uint32_t /* reserved */ : 6;
+
+ /* AXI Output 1 CbCr Configuration, Part 2 */
+ uint8_t out1cbcrburstlen:2;
+ uint32_t out1cbcrnumrows:12;
+ uint32_t out1cbcrrowincin64bitincs:12;
+ uint32_t /* reserved */ : 6;
+
+ /* AXI Output 2 Y Configuration, Part 1 */
+ uint32_t out2yimageheight:12;
+ uint32_t /* reserved */ : 4;
+ uint32_t out2yimagewidthin64bitwords:10;
+ uint32_t /* reserved */ : 6;
+
+ /* AXI Output 2 Y Configuration, Part 2 */
+ uint8_t out2yburstlen:2;
+ uint32_t out2ynumrows:12;
+ uint32_t out2yrowincin64bitincs:12;
+ uint32_t /* reserved */ : 6;
+
+ /* AXI Output 2 CbCr Configuration, Part 1 */
+ uint32_t out2cbcrimageheight:12;
+ uint32_t /* reserved */ : 4;
+ uint32_t out2cbcrimagewidtein64bitwords:10;
+ uint32_t /* reserved */ : 6;
+
+ /* AXI Output 2 CbCr Configuration, Part 2 */
+ uint8_t out2cbcrburstlen:2;
+ uint32_t out2cbcrnumrows:12;
+ uint32_t out2cbcrrowincin64bitincs:12;
+ uint32_t /* reserved */ : 6;
+
+ /* Address configuration:
+ * output1 phisycal address */
+ unsigned long output1buffer1_y_phy;
+ unsigned long output1buffer1_cbcr_phy;
+ unsigned long output1buffer2_y_phy;
+ unsigned long output1buffer2_cbcr_phy;
+ unsigned long output1buffer3_y_phy;
+ unsigned long output1buffer3_cbcr_phy;
+ unsigned long output1buffer4_y_phy;
+ unsigned long output1buffer4_cbcr_phy;
+ unsigned long output1buffer5_y_phy;
+ unsigned long output1buffer5_cbcr_phy;
+ unsigned long output1buffer6_y_phy;
+ unsigned long output1buffer6_cbcr_phy;
+ unsigned long output1buffer7_y_phy;
+ unsigned long output1buffer7_cbcr_phy;
+ unsigned long output1buffer8_y_phy;
+ unsigned long output1buffer8_cbcr_phy;
+
+ /* output2 phisycal address */
+ unsigned long output2buffer1_y_phy;
+ unsigned long output2buffer1_cbcr_phy;
+ unsigned long output2buffer2_y_phy;
+ unsigned long output2buffer2_cbcr_phy;
+ unsigned long output2buffer3_y_phy;
+ unsigned long output2buffer3_cbcr_phy;
+ unsigned long output2buffer4_y_phy;
+ unsigned long output2buffer4_cbcr_phy;
+ unsigned long output2buffer5_y_phy;
+ unsigned long output2buffer5_cbcr_phy;
+ unsigned long output2buffer6_y_phy;
+ unsigned long output2buffer6_cbcr_phy;
+ unsigned long output2buffer7_y_phy;
+ unsigned long output2buffer7_cbcr_phy;
+ unsigned long output2buffer8_y_phy;
+ unsigned long output2buffer8_cbcr_phy;
+} __packed;
+
+struct vfe_stats_we_cfg {
+ uint32_t header;
+
+ /* White Balance/Exposure Statistic Selection */
+ uint8_t wb_expstatsenable:1;
+ uint8_t wb_expstatbuspriorityselection:1;
+ unsigned int wb_expstatbuspriorityvalue:4;
+ unsigned int /* reserved */ : 26;
+
+ /* White Balance/Exposure Statistic Configuration, Part 1 */
+ uint8_t exposurestatregions:1;
+ uint8_t exposurestatsubregions:1;
+ unsigned int /* reserved */ : 14;
+
+ unsigned int whitebalanceminimumy:8;
+ unsigned int whitebalancemaximumy:8;
+
+ /* White Balance/Exposure Statistic Configuration, Part 2 */
+ uint8_t wb_expstatslopeofneutralregionline[
+ NUM_WB_EXP_NEUTRAL_REGION_LINES];
+
+ /* White Balance/Exposure Statistic Configuration, Part 3 */
+ unsigned int wb_expstatcrinterceptofneutralregionline2:12;
+ unsigned int /* reserved */ : 4;
+ unsigned int wb_expstatcbinterceptofneutralreginnline1:12;
+ unsigned int /* reserved */ : 4;
+
+ /* White Balance/Exposure Statistic Configuration, Part 4 */
+ unsigned int wb_expstatcrinterceptofneutralregionline4:12;
+ unsigned int /* reserved */ : 4;
+ unsigned int wb_expstatcbinterceptofneutralregionline3:12;
+ unsigned int /* reserved */ : 4;
+
+ /* White Balance/Exposure Statistic Output Buffer Header */
+ unsigned int wb_expmetricheaderpattern:8;
+ unsigned int /* reserved */ : 24;
+
+ /* White Balance/Exposure Statistic Output Buffers-MUST
+ * BE 64 bit ALIGNED */
+ void *wb_expstatoutputbuffer[NUM_WB_EXP_STAT_OUTPUT_BUFFERS];
+} __packed;
+
+struct vfe_stats_af_cfg {
+ uint32_t header;
+
+ /* Autofocus Statistic Selection */
+ uint8_t af_enable:1;
+ uint8_t af_busprioritysel:1;
+ unsigned int af_buspriorityval:4;
+ unsigned int /* reserved */ : 26;
+
+ /* Autofocus Statistic Configuration, Part 1 */
+ unsigned int af_singlewinvoffset:12;
+ unsigned int /* reserved */ : 4;
+ unsigned int af_singlewinhoffset:12;
+ unsigned int /* reserved */ : 3;
+ uint8_t af_winmode:1;
+
+ /* Autofocus Statistic Configuration, Part 2 */
+ unsigned int af_singglewinvh:11;
+ unsigned int /* reserved */ : 5;
+ unsigned int af_singlewinhw:11;
+ unsigned int /* reserved */ : 5;
+
+ /* Autofocus Statistic Configuration, Parts 3-6 */
+ uint8_t af_multiwingrid[NUM_AUTOFOCUS_MULTI_WINDOW_GRIDS];
+
+ /* Autofocus Statistic Configuration, Part 7 */
+ signed int af_metrichpfcoefa00:5;
+ signed int af_metrichpfcoefa04:5;
+ unsigned int af_metricmaxval:11;
+ uint8_t af_metricsel:1;
+ unsigned int /* reserved */ : 10;
+
+ /* Autofocus Statistic Configuration, Part 8 */
+ signed int af_metrichpfcoefa20:5;
+ signed int af_metrichpfcoefa21:5;
+ signed int af_metrichpfcoefa22:5;
+ signed int af_metrichpfcoefa23:5;
+ signed int af_metrichpfcoefa24:5;
+ unsigned int /* reserved */ : 7;
+
+ /* Autofocus Statistic Output Buffer Header */
+ unsigned int af_metrichp:8;
+ unsigned int /* reserved */ : 24;
+
+ /* Autofocus Statistic Output Buffers - MUST BE 64 bit ALIGNED!!! */
+ void *af_outbuf[NUM_AF_STAT_OUTPUT_BUFFERS];
+} __packed; /* VFE_StatsAutofocusConfigCmdType */
+
+struct msm_camera_frame_msg {
+ unsigned long output_y_address;
+ unsigned long output_cbcr_address;
+
+ unsigned int blacklevelevenColumn:23;
+ uint16_t reserved1:9;
+ unsigned int blackleveloddColumn:23;
+ uint16_t reserved2:9;
+
+ uint16_t greendefectpixelcount:8;
+ uint16_t reserved3:8;
+ uint16_t redbluedefectpixelcount:8;
+ uint16_t reserved4:8;
+} __packed;
+
+/* New one for 7k */
+struct msm_vfe_command_7k {
+ uint16_t queue;
+ uint16_t length;
+ void *value;
+};
+
+struct stop_event {
+ wait_queue_head_t wait;
+ int state;
+ int timeout;
+};
+
+static struct msm_free_buf *vfe2x_check_free_buffer(int id, int path);
+
+#endif /* __MSM_VFE7X_H__ */
diff --git a/drivers/media/video/msm/sensors/Makefile b/drivers/media/video/msm/sensors/Makefile
index 7b22592..a9b7bc6 100644
--- a/drivers/media/video/msm/sensors/Makefile
+++ b/drivers/media/video/msm/sensors/Makefile
@@ -6,3 +6,6 @@
obj-$(CONFIG_IMX074) += imx074_v4l2.o
obj-$(CONFIG_MT9M114) += mt9m114_v4l2.o
obj-$(CONFIG_OV2720) += ov2720.o
+obj-$(CONFIG_S5K4E1) += s5k4e1_v4l2.o
+obj-$(CONFIG_MT9E013) += mt9e013_v4l2.o
+obj-$(CONFIG_WEBCAM_OV9726) += ov9726_v4l2.o
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index d31de14..227e606 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-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
@@ -172,6 +172,42 @@
return 0;
}
+int32_t msm_sensor_setting1(struct msm_sensor_ctrl_t *s_ctrl,
+ int update_type, int res)
+{
+ int32_t rc = 0;
+ static int csi_config;
+
+ s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
+ msleep(30);
+ if (update_type == MSM_SENSOR_REG_INIT) {
+ CDBG("Register INIT\n");
+ s_ctrl->curr_csi_params = NULL;
+ msm_sensor_enable_debugfs(s_ctrl);
+ msm_sensor_write_init_settings(s_ctrl);
+ csi_config = 0;
+ } else if (update_type == MSM_SENSOR_UPDATE_PERIODIC) {
+ CDBG("PERIODIC : %d\n", res);
+ msm_sensor_write_conf_array(
+ s_ctrl->sensor_i2c_client,
+ s_ctrl->msm_sensor_reg->mode_settings, res);
+ msleep(30);
+ if (!csi_config) {
+ s_ctrl->curr_csic_params = s_ctrl->csic_params[res];
+ CDBG("CSI config in progress\n");
+ v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
+ NOTIFY_CSIC_CFG,
+ s_ctrl->curr_csic_params);
+ CDBG("CSI config is done\n");
+ mb();
+ msleep(30);
+ csi_config = 1;
+ }
+ s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
+ msleep(50);
+ }
+ return rc;
+}
int32_t msm_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl,
int update_type, int res)
{
@@ -532,6 +568,8 @@
probe_fail:
CDBG("%s_i2c_probe failed\n", client->name);
power_down:
+ if (rc > 0)
+ rc = 0;
s_ctrl->func_tbl->sensor_power_down(s_ctrl);
return rc;
}
diff --git a/drivers/media/video/msm/sensors/msm_sensor.h b/drivers/media/video/msm/sensors/msm_sensor.h
index e06f628..ba366e6 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-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
@@ -158,6 +158,8 @@
struct mutex *msm_sensor_mutex;
struct msm_camera_csi2_params *curr_csi_params;
struct msm_camera_csi2_params **csi_params;
+ struct msm_camera_csi_params **csic_params;
+ struct msm_camera_csi_params *curr_csic_params;
struct v4l2_subdev sensor_v4l2_subdev;
struct v4l2_subdev_info *sensor_v4l2_subdev_info;
@@ -218,6 +220,9 @@
int32_t msm_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl,
int update_type, int res);
+int32_t msm_sensor_setting1(struct msm_sensor_ctrl_t *s_ctrl,
+ int update_type, int res);
+
int msm_sensor_enable_debugfs(struct msm_sensor_ctrl_t *s_ctrl);
long msm_sensor_subdev_ioctl(struct v4l2_subdev *sd,
diff --git a/drivers/media/video/msm/sensors/mt9e013_v4l2.c b/drivers/media/video/msm/sensors/mt9e013_v4l2.c
new file mode 100644
index 0000000..924cbc9
--- /dev/null
+++ b/drivers/media/video/msm/sensors/mt9e013_v4l2.c
@@ -0,0 +1,507 @@
+/* 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 "msm_sensor.h"
+#define SENSOR_NAME "mt9e013"
+#define PLATFORM_DRIVER_NAME "msm_camera_mt9e013"
+#define mt9e013_obj mt9e013_##obj
+
+DEFINE_MUTEX(mt9e013_mut);
+static struct msm_sensor_ctrl_t mt9e013_s_ctrl;
+
+static struct msm_camera_i2c_reg_conf mt9e013_groupon_settings[] = {
+ {0x0104, 0x01},
+};
+
+static struct msm_camera_i2c_reg_conf mt9e013_groupoff_settings[] = {
+ {0x0104, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf mt9e013_prev_settings[] = {
+ {0x0300, 0x0004},/*VT_PIX_CLK_DIV*/
+ {0x0302, 0x0001},/*VT_SYS_CLK_DIV*/
+ {0x0304, 0x0002},/*PRE_PLL_CLK_DIV*/
+ {0x0306, 0x003A},/*PLL_MULTIPLIER*/
+ {0x0308, 0x000A},/*OP_PIX_CLK_DIV*/
+ {0x030A, 0x0001},/*OP_SYS_CLK_DIV*/
+ /*Output Size (1632x1224)*/
+ {0x0344, 0x0008},/*X_ADDR_START*/
+ {0x0348, 0x0CC9},/*X_ADDR_END*/
+ {0x0346, 0x0008},/*Y_ADDR_START*/
+ {0x034A, 0x0999},/*Y_ADDR_END*/
+ {0x034C, 0x0660},/*X_OUTPUT_SIZE*/
+ {0x034E, 0x04C8},/*Y_OUTPUT_SIZE*/
+ {0x306E, 0xFCB0},/*DATAPATH_SELECT*/
+ {0x3040, 0x04C3},/*READ_MODE*/
+ {0x3178, 0x0000},/*ANALOG_CONTROL5*/
+ {0x3ED0, 0x1E24},/*DAC_LD_4_5*/
+ {0x0400, 0x0002},/*SCALING_MODE*/
+ {0x0404, 0x0010},/*SCALE_M*/
+ /*Timing configuration*/
+ {0x0342, 0x1018},/*LINE_LENGTH_PCK*/
+ {0x0340, 0x055B},/*FRAME_LENGTH_LINES*/
+ {0x0202, 0x0557},/*COARSE_INTEGRATION_TIME*/
+ {0x3014, 0x0846},/*FINE_INTEGRATION_TIME_*/
+ {0x3010, 0x0130},/*FINE_CORRECTION*/
+};
+
+static struct msm_camera_i2c_reg_conf mt9e013_snap_settings[] = {
+ {0x0300, 0x0004},/*VT_PIX_CLK_DIV*/
+ {0x0302, 0x0001},/*VT_SYS_CLK_DIV*/
+ {0x0304, 0x0002},/*PRE_PLL_CLK_DIV*/
+ {0x0306, 0x003A},/*PLL_MULTIPLIER*/
+ {0x0308, 0x000A},/*OP_PIX_CLK_DIV*/
+ {0x030A, 0x0001},/*OP_SYS_CLK_DIV*/
+ /*Output Size (3264x2448)*/
+ {0x0344, 0x0000},/*X_ADDR_START */
+ {0x0348, 0x0CCF},/*X_ADDR_END*/
+ {0x0346, 0x0000},/*Y_ADDR_START */
+ {0x034A, 0x099F},/*Y_ADDR_END*/
+ {0x034C, 0x0CD0},/*X_OUTPUT_SIZE*/
+ {0x034E, 0x09A0},/*Y_OUTPUT_SIZE*/
+ {0x306E, 0xFC80},/*DATAPATH_SELECT*/
+ {0x3040, 0x0041},/*READ_MODE*/
+ {0x3178, 0x0000},/*ANALOG_CONTROL5*/
+ {0x3ED0, 0x1E24},/*DAC_LD_4_5*/
+ {0x0400, 0x0000},/*SCALING_MODE*/
+ {0x0404, 0x0010},/*SCALE_M*/
+ /*Timing configuration*/
+ {0x0342, 0x13F8},/*LINE_LENGTH_PCK*/
+ {0x0340, 0x0A2F},/*FRAME_LENGTH_LINES*/
+ {0x0202, 0x0A1F},/*COARSE_INTEGRATION_TIME*/
+ {0x3014, 0x03F6},/*FINE_INTEGRATION_TIME_ */
+ {0x3010, 0x0078},/*FINE_CORRECTION*/
+};
+
+static struct msm_camera_i2c_reg_conf mt9e013_hfr60_settings[] = {
+ {0x0300, 0x0005},/*VT_PIX_CLK_DIV*/
+ {0x0302, 0x0001},/*VT_SYS_CLK_DIV*/
+ {0x0304, 0x0002},/*PRE_PLL_CLK_DIV*/
+ {0x0306, 0x0029},/*PLL_MULTIPLIER*/
+ {0x0308, 0x000A},/*OP_PIX_CLK_DIV*/
+ {0x030A, 0x0001},/*OP_SYS_CLK_DIV*/
+ {0x0344, 0x0008},/*X_ADDR_START*/
+ {0x0348, 0x0685},/*X_ADDR_END*/
+ {0x0346, 0x013a},/*Y_ADDR_START*/
+ {0x034A, 0x055B},/*Y_ADDR_END*/
+ {0x034C, 0x0340},/*X_OUTPUT_SIZE*/
+ {0x034E, 0x0212},/*Y_OUTPUT_SIZE*/
+ {0x306E, 0xFC80},/*DATAPATH_SELECT*/
+ {0x3040, 0x00C3},/*READ_MODE*/
+ {0x3178, 0x0000},/*ANALOG_CONTROL5*/
+ {0x3ED0, 0x1E24},/*DAC_LD_4_5*/
+ {0x0400, 0x0000},/*SCALING_MODE*/
+ {0x0404, 0x0010},/*SCALE_M*/
+ /*Timing configuration*/
+ {0x0342, 0x0970},/*LINE_LENGTH_PCK*/
+ {0x0340, 0x02A1},/*FRAME_LENGTH_LINES*/
+ {0x0202, 0x02A1},/*COARSE_INTEGRATION_TIME*/
+ {0x3014, 0x03F6},/*FINE_INTEGRATION_TIME_*/
+ {0x3010, 0x0078},/*FINE_CORRECTION*/
+};
+
+static struct msm_camera_i2c_reg_conf mt9e013_hfr90_settings[] = {
+ {0x0300, 0x0005},/*VT_PIX_CLK_DIV*/
+ {0x0302, 0x0001},/*VT_SYS_CLK_DIV*/
+ {0x0304, 0x0002},/*PRE_PLL_CLK_DIV*/
+ {0x0306, 0x003D},/*PLL_MULTIPLIER*/
+ {0x0308, 0x000A},/*OP_PIX_CLK_DIV*/
+ {0x030A, 0x0001},/*OP_SYS_CLK_DIV*/
+ {0x0344, 0x0008},/*X_ADDR_START*/
+ {0x0348, 0x0685},/*X_ADDR_END*/
+ {0x0346, 0x013a},/*Y_ADDR_START*/
+ {0x034A, 0x055B},/*Y_ADDR_END*/
+ {0x034C, 0x0340},/*X_OUTPUT_SIZE*/
+ {0x034E, 0x0212},/*Y_OUTPUT_SIZE*/
+ {0x306E, 0xFC80},/*DATAPATH_SELECT*/
+ {0x3040, 0x00C3},/*READ_MODE*/
+ {0x3178, 0x0000},/*ANALOG_CONTROL5*/
+ {0x3ED0, 0x1E24},/*DAC_LD_4_5*/
+ {0x0400, 0x0000},/*SCALING_MODE*/
+ {0x0404, 0x0010},/*SCALE_M*/
+ /*Timing configuration*/
+ {0x0342, 0x0970},/*LINE_LENGTH_PCK*/
+ {0x0340, 0x02A1},/*FRAME_LENGTH_LINES*/
+ {0x0202, 0x02A1},/*COARSE_INTEGRATION_TIME*/
+ {0x3014, 0x03F6},/*FINE_INTEGRATION_TIME_*/
+ {0x3010, 0x0078},/*FINE_CORRECTION*/
+};
+
+static struct msm_camera_i2c_reg_conf mt9e013_hfr120_settings[] = {
+ {0x0300, 0x0005},/*VT_PIX_CLK_DIV*/
+ {0x0302, 0x0001},/*VT_SYS_CLK_DIV*/
+ {0x0304, 0x0002},/*PRE_PLL_CLK_DIV*/
+ {0x0306, 0x0052},/*PLL_MULTIPLIER*/
+ {0x0308, 0x000A},/*OP_PIX_CLK_DIV*/
+ {0x030A, 0x0001},/*OP_SYS_CLK_DIV*/
+ {0x0344, 0x0008},/*X_ADDR_START*/
+ {0x0348, 0x0685},/*X_ADDR_END*/
+ {0x0346, 0x013a},/*Y_ADDR_START*/
+ {0x034A, 0x055B},/*Y_ADDR_END*/
+ {0x034C, 0x0340},/*X_OUTPUT_SIZE*/
+ {0x034E, 0x0212},/*Y_OUTPUT_SIZE*/
+ {0x306E, 0xFC80},/*DATAPATH_SELECT*/
+ {0x3040, 0x00C3},/*READ_MODE*/
+ {0x3178, 0x0000},/*ANALOG_CONTROL5*/
+ {0x3ED0, 0x1E24},/*DAC_LD_4_5*/
+ {0x0400, 0x0000},/*SCALING_MODE*/
+ {0x0404, 0x0010},/*SCALE_M*/
+ /*Timing configuration*/
+ {0x0342, 0x0970},/*LINE_LENGTH_PCK*/
+ {0x0340, 0x02A1},/*FRAME_LENGTH_LINES*/
+ {0x0202, 0x02A1},/*COARSE_INTEGRATION_TIME*/
+ {0x3014, 0x03F6},/*FINE_INTEGRATION_TIME_*/
+ {0x3010, 0x0078},/*FINE_CORRECTION*/
+};
+
+static struct msm_camera_i2c_reg_conf mt9e013_recommend_settings[] = {
+ /*Disable embedded data*/
+ {0x3064, 0x7800},/*SMIA_TEST*/
+ /*configure 2-lane MIPI*/
+ {0x31AE, 0x0202},/*SERIAL_FORMAT*/
+ {0x31B8, 0x0E3F},/*MIPI_TIMING_2*/
+ /*set data to RAW10 format*/
+ {0x0112, 0x0A0A},/*CCP_DATA_FORMAT*/
+ {0x30F0, 0x8000},/*VCM CONTROL*/
+
+ {0x3044, 0x0590},
+ {0x306E, 0xFC80},
+ {0x30B2, 0xC000},
+ {0x30D6, 0x0800},
+ {0x316C, 0xB42F},
+ {0x316E, 0x869C},
+ {0x3170, 0x210E},
+ {0x317A, 0x010E},
+ {0x31E0, 0x1FB9},
+ {0x31E6, 0x07FC},
+ {0x37C0, 0x0000},
+ {0x37C2, 0x0000},
+ {0x37C4, 0x0000},
+ {0x37C6, 0x0000},
+ {0x3E02, 0x8801},
+ {0x3E04, 0x2301},
+ {0x3E06, 0x8449},
+ {0x3E08, 0x6841},
+ {0x3E0A, 0x400C},
+ {0x3E0C, 0x1001},
+ {0x3E0E, 0x2103},
+ {0x3E10, 0x4B41},
+ {0x3E12, 0x4B26},
+ {0x3E16, 0x8802},
+ {0x3E18, 0x84FF},
+ {0x3E1A, 0x8601},
+ {0x3E1C, 0x8401},
+ {0x3E1E, 0x840A},
+ {0x3E20, 0xFF00},
+ {0x3E22, 0x8401},
+ {0x3E24, 0x00FF},
+ {0x3E26, 0x0088},
+ {0x3E28, 0x2E8A},
+ {0x3E32, 0x8801},
+ {0x3E34, 0x4024},
+ {0x3E38, 0x8469},
+ {0x3E3C, 0x2301},
+ {0x3E3E, 0x3E25},
+ {0x3E40, 0x1C01},
+ {0x3E42, 0x8486},
+ {0x3E44, 0x8401},
+ {0x3E46, 0x00FF},
+ {0x3E48, 0x8401},
+ {0x3E4A, 0x8601},
+ {0x3E4C, 0x8402},
+ {0x3E4E, 0x00FF},
+ {0x3E50, 0x6623},
+ {0x3E52, 0x8340},
+ {0x3E54, 0x00FF},
+ {0x3E56, 0x4A42},
+ {0x3E58, 0x2203},
+ {0x3E5A, 0x674D},
+ {0x3E5C, 0x3F25},
+ {0x3E5E, 0x846A},
+ {0x3E60, 0x4C01},
+ {0x3E62, 0x8401},
+ {0x3E66, 0x3901},
+ {0x3ECC, 0x00EB},
+ {0x3ED0, 0x1E24},
+ {0x3ED4, 0xAFC4},
+ {0x3ED6, 0x909B},
+ {0x3ED8, 0x0006},
+ {0x3EDA, 0xCFC6},
+ {0x3EDC, 0x4FE4},
+ {0x3EE0, 0x2424},
+ {0x3EE2, 0x9797},
+ {0x3EE4, 0xC100},
+ {0x3EE6, 0x0540}
+};
+
+static struct v4l2_subdev_info mt9e013_subdev_info[] = {
+ {
+ .code = V4L2_MBUS_FMT_SBGGR10_1X10,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .fmt = 1,
+ .order = 0,
+ },
+ /* more can be supported, to be added later */
+};
+
+static struct msm_camera_i2c_conf_array mt9e013_init_conf[] = {
+ {&mt9e013_recommend_settings[0],
+ ARRAY_SIZE(mt9e013_recommend_settings), 0, MSM_CAMERA_I2C_WORD_DATA}
+};
+
+static struct msm_camera_i2c_conf_array mt9e013_confs[] = {
+ {&mt9e013_snap_settings[0],
+ ARRAY_SIZE(mt9e013_snap_settings), 0, MSM_CAMERA_I2C_WORD_DATA},
+ {&mt9e013_prev_settings[0],
+ ARRAY_SIZE(mt9e013_prev_settings), 0, MSM_CAMERA_I2C_WORD_DATA},
+ {&mt9e013_hfr60_settings[0],
+ ARRAY_SIZE(mt9e013_hfr60_settings), 0, MSM_CAMERA_I2C_WORD_DATA},
+ {&mt9e013_hfr90_settings[0],
+ ARRAY_SIZE(mt9e013_hfr90_settings), 0, MSM_CAMERA_I2C_WORD_DATA},
+ {&mt9e013_hfr120_settings[0],
+ ARRAY_SIZE(mt9e013_hfr120_settings), 0, MSM_CAMERA_I2C_WORD_DATA},
+};
+
+static struct msm_sensor_output_info_t mt9e013_dimensions[] = {
+ {
+ .x_output = 0xCD0,
+ .y_output = 0x9A0,
+ .line_length_pclk = 0x13F8,
+ .frame_length_lines = 0xA2F,
+ .vt_pixel_clk = 174000000,
+ .op_pixel_clk = 174000000,
+ .binning_factor = 1,
+ },
+ {
+ .x_output = 0x660,
+ .y_output = 0x4C8,
+ .line_length_pclk = 0x1018,
+ .frame_length_lines = 0x55B,
+ .vt_pixel_clk = 174000000,
+ .op_pixel_clk = 174000000,
+ .binning_factor = 1,
+ },
+ {
+ .x_output = 0x340,
+ .y_output = 0x212,
+ .line_length_pclk = 0x970,
+ .frame_length_lines = 0x2A1,
+ .vt_pixel_clk = 98400000,
+ .op_pixel_clk = 98400000,
+ .binning_factor = 1,
+ },
+ {
+ .x_output = 0x340,
+ .y_output = 0x212,
+ .line_length_pclk = 0x970,
+ .frame_length_lines = 0x2A1,
+ .vt_pixel_clk = 146400000,
+ .op_pixel_clk = 146400000,
+ .binning_factor = 1,
+ },
+ {
+ .x_output = 0x340,
+ .y_output = 0x212,
+ .line_length_pclk = 0x970,
+ .frame_length_lines = 0x2A1,
+ .vt_pixel_clk = 196800000,
+ .op_pixel_clk = 196800000,
+ .binning_factor = 1,
+ },
+};
+
+static struct msm_camera_csi_params mt9e013_csi_params = {
+ .data_format = CSI_10BIT,
+ .lane_cnt = 2,
+ .lane_assign = 0xe4,
+ .dpcm_scheme = 0,
+ .settle_cnt = 0x18,
+};
+
+static struct msm_camera_csi_params *mt9e013_csi_params_array[] = {
+ &mt9e013_csi_params,
+ &mt9e013_csi_params,
+ &mt9e013_csi_params,
+ &mt9e013_csi_params,
+ &mt9e013_csi_params,
+};
+
+static struct msm_sensor_output_reg_addr_t mt9e013_reg_addr = {
+ .x_output = 0x34C,
+ .y_output = 0x34E,
+ .line_length_pclk = 0x342,
+ .frame_length_lines = 0x340,
+};
+
+static struct msm_sensor_id_info_t mt9e013_id_info = {
+ .sensor_id_reg_addr = 0x0,
+ .sensor_id = 0x4B00,
+};
+
+static struct msm_sensor_exp_gain_info_t mt9e013_exp_gain_info = {
+ .coarse_int_time_addr = 0x202,
+ .global_gain_addr = 0x305E,
+ .vert_offset = 0,
+};
+
+static int32_t mt9e013_write_exp_gain(struct msm_sensor_ctrl_t *s_ctrl,
+ uint16_t gain, uint32_t line)
+{
+ uint32_t fl_lines;
+ fl_lines =
+ (s_ctrl->curr_frame_length_lines * s_ctrl->fps_divider) / Q10;
+
+ s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->global_gain_addr, gain | 0x1000,
+ MSM_CAMERA_I2C_WORD_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->coarse_int_time_addr, line,
+ MSM_CAMERA_I2C_WORD_DATA);
+ s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
+ return 0;
+}
+
+static int32_t mt9e013_write_exp_snapshot_gain(struct msm_sensor_ctrl_t *s_ctrl,
+ uint16_t gain, uint32_t line)
+{
+ uint32_t fl_lines;
+ fl_lines =
+ (s_ctrl->curr_frame_length_lines * s_ctrl->fps_divider) / Q10;
+
+ s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->global_gain_addr, gain | 0x1000,
+ MSM_CAMERA_I2C_WORD_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->coarse_int_time_addr, line,
+ MSM_CAMERA_I2C_WORD_DATA);
+ s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ 0x301A, (0x065C|0x2), MSM_CAMERA_I2C_WORD_DATA);
+
+ return 0;
+}
+static void mt9e013_start_stream(struct msm_sensor_ctrl_t *s_ctrl)
+{
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ 0x301A, 0x8250, MSM_CAMERA_I2C_WORD_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ 0x301A, 0x8650, MSM_CAMERA_I2C_WORD_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ 0x301A, 0x8658, MSM_CAMERA_I2C_WORD_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ 0x0104, 0x00, MSM_CAMERA_I2C_BYTE_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ 0x301A, 0x065C, MSM_CAMERA_I2C_WORD_DATA);
+}
+
+static void mt9e013_stop_stream(struct msm_sensor_ctrl_t *s_ctrl)
+{
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ 0x301A, 0x0058, MSM_CAMERA_I2C_WORD_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ 0x301A, 0x0050, MSM_CAMERA_I2C_WORD_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ 0x0104, 0x01, MSM_CAMERA_I2C_BYTE_DATA);
+}
+
+static const struct i2c_device_id mt9e013_i2c_id[] = {
+ {SENSOR_NAME, (kernel_ulong_t)&mt9e013_s_ctrl},
+ { }
+};
+
+static struct i2c_driver mt9e013_i2c_driver = {
+ .id_table = mt9e013_i2c_id,
+ .probe = msm_sensor_i2c_probe,
+ .driver = {
+ .name = SENSOR_NAME,
+ },
+};
+
+static struct msm_camera_i2c_client mt9e013_sensor_i2c_client = {
+ .addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static int __init msm_sensor_init_module(void)
+{
+ return i2c_add_driver(&mt9e013_i2c_driver);
+}
+
+static struct v4l2_subdev_core_ops mt9e013_subdev_core_ops = {
+ .ioctl = msm_sensor_subdev_ioctl,
+ .s_power = msm_sensor_power,
+};
+
+static struct v4l2_subdev_video_ops mt9e013_subdev_video_ops = {
+ .enum_mbus_fmt = msm_sensor_v4l2_enum_fmt,
+};
+
+static struct v4l2_subdev_ops mt9e013_subdev_ops = {
+ .core = &mt9e013_subdev_core_ops,
+ .video = &mt9e013_subdev_video_ops,
+};
+
+static struct msm_sensor_fn_t mt9e013_func_tbl = {
+ .sensor_start_stream = mt9e013_start_stream,
+ .sensor_stop_stream = mt9e013_stop_stream,
+ .sensor_group_hold_on = msm_sensor_group_hold_on,
+ .sensor_group_hold_off = msm_sensor_group_hold_off,
+ .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_set_sensor_mode = msm_sensor_set_sensor_mode,
+ .sensor_mode_init = msm_sensor_mode_init,
+ .sensor_get_output_info = msm_sensor_get_output_info,
+ .sensor_config = msm_sensor_config,
+ .sensor_power_up = msm_sensor_power_up,
+ .sensor_power_down = msm_sensor_power_down,
+};
+
+static struct msm_sensor_reg_t mt9e013_regs = {
+ .default_data_type = MSM_CAMERA_I2C_BYTE_DATA,
+ .group_hold_on_conf = mt9e013_groupon_settings,
+ .group_hold_on_conf_size = ARRAY_SIZE(mt9e013_groupon_settings),
+ .group_hold_off_conf = mt9e013_groupoff_settings,
+ .group_hold_off_conf_size =
+ ARRAY_SIZE(mt9e013_groupoff_settings),
+ .init_settings = &mt9e013_init_conf[0],
+ .init_size = ARRAY_SIZE(mt9e013_init_conf),
+ .mode_settings = &mt9e013_confs[0],
+ .output_settings = &mt9e013_dimensions[0],
+ .num_conf = ARRAY_SIZE(mt9e013_confs),
+};
+
+static struct msm_sensor_ctrl_t mt9e013_s_ctrl = {
+ .msm_sensor_reg = &mt9e013_regs,
+ .sensor_i2c_client = &mt9e013_sensor_i2c_client,
+ .sensor_i2c_addr = 0x6C,
+ .sensor_output_reg_addr = &mt9e013_reg_addr,
+ .sensor_id_info = &mt9e013_id_info,
+ .sensor_exp_gain_info = &mt9e013_exp_gain_info,
+ .cam_mode = MSM_SENSOR_MODE_INVALID,
+ .csic_params = &mt9e013_csi_params_array[0],
+ .msm_sensor_mutex = &mt9e013_mut,
+ .sensor_i2c_driver = &mt9e013_i2c_driver,
+ .sensor_v4l2_subdev_info = mt9e013_subdev_info,
+ .sensor_v4l2_subdev_info_size = ARRAY_SIZE(mt9e013_subdev_info),
+ .sensor_v4l2_subdev_ops = &mt9e013_subdev_ops,
+ .func_tbl = &mt9e013_func_tbl,
+};
+
+module_init(msm_sensor_init_module);
+MODULE_DESCRIPTION("Aptina 8MP Bayer sensor driver");
+MODULE_LICENSE("GPL v2");
+
+
diff --git a/drivers/media/video/msm/sensors/ov9726_v4l2.c b/drivers/media/video/msm/sensors/ov9726_v4l2.c
new file mode 100644
index 0000000..e345717
--- /dev/null
+++ b/drivers/media/video/msm/sensors/ov9726_v4l2.c
@@ -0,0 +1,280 @@
+/* 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 "msm_sensor.h"
+#define SENSOR_NAME "ov9726"
+#define PLATFORM_DRIVER_NAME "msm_camera_ov9726"
+#define ov9726_obj ov9726_##obj
+
+DEFINE_MUTEX(ov9726_mut);
+static struct msm_sensor_ctrl_t ov9726_s_ctrl;
+
+static struct msm_camera_i2c_reg_conf ov9726_start_settings[] = {
+ {0x0100, 0x01},
+};
+
+static struct msm_camera_i2c_reg_conf ov9726_stop_settings[] = {
+ {0x0100, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf ov9726_groupon_settings[] = {
+ {0x0104, 0x01},
+};
+
+static struct msm_camera_i2c_reg_conf ov9726_groupoff_settings[] = {
+ {0x0104, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf ov9726_prev_settings[] = {
+};
+
+static struct msm_camera_i2c_reg_conf ov9726_recommend_settings[] = {
+ {0x0103, 0x01}, /* SOFTWARE_RESET */
+ {0x3026, 0x00}, /* OUTPUT_SELECT01 */
+ {0x3027, 0x00}, /* OUTPUT_SELECT02 */
+ {0x3002, 0xe8}, /* IO_CTRL00 */
+ {0x3004, 0x03}, /* IO_CTRL01 */
+ {0x3005, 0xff}, /* IO_CTRL02 */
+ {0x3703, 0x42},
+ {0x3704, 0x10},
+ {0x3705, 0x45},
+ {0x3603, 0xaa},
+ {0x3632, 0x2f},
+ {0x3620, 0x66},
+ {0x3621, 0xc0},
+ {0x0340, 0x03}, /* FRAME_LENGTH_LINES_HI */
+ {0x0341, 0xC1}, /* FRAME_LENGTH_LINES_LO */
+ {0x0342, 0x06}, /* LINE_LENGTH_PCK_HI */
+ {0x0343, 0x80}, /* LINE_LENGTH_PCK_LO */
+ {0x0202, 0x03}, /* COARSE_INTEGRATION_TIME_HI */
+ {0x0203, 0x43}, /* COARSE_INTEGRATION_TIME_LO */
+ {0x3833, 0x04},
+ {0x3835, 0x02},
+ {0x4702, 0x04},
+ {0x4704, 0x00}, /* DVP_CTRL01 */
+ {0x4706, 0x08},
+ {0x5052, 0x01},
+ {0x3819, 0x6e},
+ {0x3817, 0x94},
+ {0x3a18, 0x00}, /* AEC_GAIN_CEILING_HI */
+ {0x3a19, 0x7f}, /* AEC_GAIN_CEILING_LO */
+ {0x404e, 0x7e},
+ {0x3631, 0x52},
+ {0x3633, 0x50},
+ {0x3630, 0xd2},
+ {0x3604, 0x08},
+ {0x3601, 0x40},
+ {0x3602, 0x14},
+ {0x3610, 0xa0},
+ {0x3612, 0x20},
+ {0x034c, 0x05}, /* X_OUTPUT_SIZE_HI */
+ {0x034d, 0x10}, /* X_OUTPUT_SIZE_LO */
+ {0x034e, 0x03}, /* Y_OUTPUT_SIZE_HI */
+ {0x034f, 0x28}, /* Y_OUTPUT_SIZE_LO */
+ {0x0340, 0x03}, /* FRAME_LENGTH_LINES_HI */
+ {0x0341, 0xC1}, /* FRAME_LENGTH_LINES_LO */
+ {0x0342, 0x06}, /* LINE_LENGTH_PCK_HI */
+ {0x0343, 0x80}, /* LINE_LENGTH_PCK_LO */
+ {0x0202, 0x03}, /* COARSE_INTEGRATION_TIME_HI */
+ {0x0203, 0x43}, /* COARSE_INTEGRATION_TIME_LO */
+ {0x0303, 0x01}, /* VT_SYS_CLK_DIV_LO */
+ {0x3002, 0x00}, /* IO_CTRL00 */
+ {0x3004, 0x00}, /* IO_CTRL01 */
+ {0x3005, 0x00}, /* IO_CTRL02 */
+ {0x4801, 0x0f}, /* MIPI_CTRL01 */
+ {0x4803, 0x05}, /* MIPI_CTRL03 */
+ {0x4601, 0x16}, /* VFIFO_READ_CONTROL */
+ {0x3014, 0x05}, /* SC_CMMN_MIPI / SC_CTRL00 */
+ {0x3104, 0x80},
+ {0x0305, 0x04}, /* PRE_PLL_CLK_DIV_LO */
+ {0x0307, 0x64}, /* PLL_MULTIPLIER_LO */
+ {0x300c, 0x02},
+ {0x300d, 0x20},
+ {0x300e, 0x01},
+ {0x3010, 0x01},
+ {0x460e, 0x81}, /* VFIFO_CONTROL00 */
+ {0x0101, 0x01}, /* IMAGE_ORIENTATION */
+ {0x3707, 0x14},
+ {0x3622, 0x9f},
+ {0x5047, 0x3D}, /* ISP_CTRL47 */
+ {0x4002, 0x45}, /* BLC_CTRL02 */
+ {0x5000, 0x06}, /* ISP_CTRL0 */
+ {0x5001, 0x00}, /* ISP_CTRL1 */
+ {0x3406, 0x00}, /* AWB_MANUAL_CTRL */
+ {0x3503, 0x13}, /* AEC_ENABLE */
+ {0x4005, 0x18}, /* BLC_CTRL05 */
+ {0x4837, 0x21},
+ {0x0100, 0x01}, /* MODE_SELECT */
+ {0x3a0f, 0x64}, /* AEC_CTRL0F */
+ {0x3a10, 0x54}, /* AEC_CTRL10 */
+ {0x3a11, 0xc2}, /* AEC_CTRL11 */
+ {0x3a1b, 0x64}, /* AEC_CTRL1B */
+ {0x3a1e, 0x54}, /* AEC_CTRL1E */
+ {0x3a1a, 0x05}, /* AEC_DIFF_MAX */
+};
+
+static struct v4l2_subdev_info ov9726_subdev_info[] = {
+ {
+ .code = V4L2_MBUS_FMT_SBGGR10_1X10,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .fmt = 1,
+ .order = 0,
+ },
+ /* more can be supported, to be added later */
+};
+
+static struct msm_camera_i2c_conf_array ov9726_init_conf[] = {
+ {&ov9726_recommend_settings[0],
+ ARRAY_SIZE(ov9726_recommend_settings), 0, MSM_CAMERA_I2C_BYTE_DATA}
+};
+
+static struct msm_camera_i2c_conf_array ov9726_confs[] = {
+ {&ov9726_prev_settings[0],
+ ARRAY_SIZE(ov9726_prev_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+};
+
+static struct msm_sensor_output_info_t ov9726_dimensions[] = {
+ {
+ .x_output = 0x510, /* 1296 */
+ .y_output = 0x328, /* 808 */
+ .line_length_pclk = 0x680, /* 1664 */
+ .frame_length_lines = 0x3C1, /* 961 */
+ .vt_pixel_clk = 320000000,
+ .op_pixel_clk = 320000000,
+ .binning_factor = 1,
+ },
+};
+
+static struct msm_camera_csi_params ov9726_csi_params = {
+ .data_format = CSI_10BIT,
+ .lane_cnt = 1,
+ .lane_assign = 0xe4,
+ .dpcm_scheme = 0,
+ .settle_cnt = 7,
+};
+
+static struct msm_camera_csi_params *ov9726_csi_params_array[] = {
+ &ov9726_csi_params,
+};
+
+static struct msm_sensor_output_reg_addr_t ov9726_reg_addr = {
+ .x_output = 0x034c,
+ .y_output = 0x034e,
+ .line_length_pclk = 0x0342,
+ .frame_length_lines = 0x0340,
+};
+
+static struct msm_sensor_id_info_t ov9726_id_info = {
+ .sensor_id_reg_addr = 0x0000,
+ .sensor_id = 0x9726,
+};
+
+static struct msm_sensor_exp_gain_info_t ov9726_exp_gain_info = {
+ .coarse_int_time_addr = 0x0202,
+ .global_gain_addr = 0x0204,
+ .vert_offset = 6,
+};
+
+static const struct i2c_device_id ov9726_i2c_id[] = {
+ {SENSOR_NAME, (kernel_ulong_t)&ov9726_s_ctrl},
+ { }
+};
+
+static struct i2c_driver ov9726_i2c_driver = {
+ .id_table = ov9726_i2c_id,
+ .probe = msm_sensor_i2c_probe,
+ .driver = {
+ .name = SENSOR_NAME,
+ },
+};
+
+static struct msm_camera_i2c_client ov9726_sensor_i2c_client = {
+ .addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static int __init msm_sensor_init_module(void)
+{
+ return i2c_add_driver(&ov9726_i2c_driver);
+}
+
+static struct v4l2_subdev_core_ops ov9726_subdev_core_ops = {
+ .ioctl = msm_sensor_subdev_ioctl,
+ .s_power = msm_sensor_power,
+};
+
+static struct v4l2_subdev_video_ops ov9726_subdev_video_ops = {
+ .enum_mbus_fmt = msm_sensor_v4l2_enum_fmt,
+};
+
+static struct v4l2_subdev_ops ov9726_subdev_ops = {
+ .core = &ov9726_subdev_core_ops,
+ .video = &ov9726_subdev_video_ops,
+};
+
+static struct msm_sensor_fn_t ov9726_func_tbl = {
+ .sensor_start_stream = msm_sensor_start_stream,
+ .sensor_stop_stream = msm_sensor_stop_stream,
+ .sensor_group_hold_on = msm_sensor_group_hold_on,
+ .sensor_group_hold_off = msm_sensor_group_hold_off,
+ .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_set_sensor_mode = msm_sensor_set_sensor_mode,
+ .sensor_mode_init = msm_sensor_mode_init,
+ .sensor_get_output_info = msm_sensor_get_output_info,
+ .sensor_config = msm_sensor_config,
+ .sensor_power_up = msm_sensor_power_up,
+ .sensor_power_down = msm_sensor_power_down,
+};
+
+static struct msm_sensor_reg_t ov9726_regs = {
+ .default_data_type = MSM_CAMERA_I2C_BYTE_DATA,
+ .start_stream_conf = ov9726_start_settings,
+ .start_stream_conf_size = ARRAY_SIZE(ov9726_start_settings),
+ .stop_stream_conf = ov9726_stop_settings,
+ .stop_stream_conf_size = ARRAY_SIZE(ov9726_stop_settings),
+ .group_hold_on_conf = ov9726_groupon_settings,
+ .group_hold_on_conf_size = ARRAY_SIZE(ov9726_groupon_settings),
+ .group_hold_off_conf = ov9726_groupoff_settings,
+ .group_hold_off_conf_size =
+ ARRAY_SIZE(ov9726_groupoff_settings),
+ .init_settings = &ov9726_init_conf[0],
+ .init_size = ARRAY_SIZE(ov9726_init_conf),
+ .mode_settings = &ov9726_confs[0],
+ .output_settings = &ov9726_dimensions[0],
+ .num_conf = ARRAY_SIZE(ov9726_confs),
+};
+
+static struct msm_sensor_ctrl_t ov9726_s_ctrl = {
+ .msm_sensor_reg = &ov9726_regs,
+ .sensor_i2c_client = &ov9726_sensor_i2c_client,
+ .sensor_i2c_addr = 0x20,
+ .sensor_output_reg_addr = &ov9726_reg_addr,
+ .sensor_id_info = &ov9726_id_info,
+ .sensor_exp_gain_info = &ov9726_exp_gain_info,
+ .cam_mode = MSM_SENSOR_MODE_INVALID,
+ .csic_params = &ov9726_csi_params_array[0],
+ .msm_sensor_mutex = &ov9726_mut,
+ .sensor_i2c_driver = &ov9726_i2c_driver,
+ .sensor_v4l2_subdev_info = ov9726_subdev_info,
+ .sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov9726_subdev_info),
+ .sensor_v4l2_subdev_ops = &ov9726_subdev_ops,
+ .func_tbl = &ov9726_func_tbl,
+};
+
+module_init(msm_sensor_init_module);
+MODULE_DESCRIPTION("Omnivision WXGA Bayer sensor driver");
+MODULE_LICENSE("GPL v2");
+
+
diff --git a/drivers/media/video/msm/sensors/s5k4e1_v4l2.c b/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
new file mode 100644
index 0000000..1f99119
--- /dev/null
+++ b/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
@@ -0,0 +1,503 @@
+/* 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 "msm_sensor.h"
+#define SENSOR_NAME "s5k4e1"
+#define PLATFORM_DRIVER_NAME "msm_camera_s5k4e1"
+#define s5k4e1_obj s5k4e1_##obj
+#define MSB 1
+#define LSB 0
+
+DEFINE_MUTEX(s5k4e1_mut);
+static struct msm_sensor_ctrl_t s5k4e1_s_ctrl;
+
+static struct msm_camera_i2c_reg_conf s5k4e1_start_settings[] = {
+ {0x0100, 0x01},
+};
+
+static struct msm_camera_i2c_reg_conf s5k4e1_stop_settings[] = {
+ {0x0100, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf s5k4e1_groupon_settings[] = {
+ {0x0104, 0x01},
+};
+
+static struct msm_camera_i2c_reg_conf s5k4e1_groupoff_settings[] = {
+ {0x0104, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf s5k4e1_prev_settings[] = {
+ /* output size (1304 x 980) */
+ {0x30A9, 0x02},/* Horizontal Binning On */
+ {0x300E, 0xEB},/* Vertical Binning On */
+ {0x0387, 0x03},/* y_odd_inc 03(10b AVG) */
+ {0x0344, 0x00},/* x_addr_start 0 */
+ {0x0345, 0x00},
+ {0x0348, 0x0A},/* x_addr_end 2607 */
+ {0x0349, 0x2F},
+ {0x0346, 0x00},/* y_addr_start 0 */
+ {0x0347, 0x00},
+ {0x034A, 0x07},/* y_addr_end 1959 */
+ {0x034B, 0xA7},
+ {0x0380, 0x00},/* x_even_inc 1 */
+ {0x0381, 0x01},
+ {0x0382, 0x00},/* x_odd_inc 1 */
+ {0x0383, 0x01},
+ {0x0384, 0x00},/* y_even_inc 1 */
+ {0x0385, 0x01},
+ {0x0386, 0x00},/* y_odd_inc 3 */
+ {0x0387, 0x03},
+ {0x034C, 0x05},/* x_output_size 1304 */
+ {0x034D, 0x18},
+ {0x034E, 0x03},/* y_output_size 980 */
+ {0x034F, 0xd4},
+ {0x30BF, 0xAB},/* outif_enable[7], data_type[5:0](2Bh = bayer 10bit} */
+ {0x30C0, 0xA0},/* video_offset[7:4] 3260%12 */
+ {0x30C8, 0x06},/* video_data_length 1600 = 1304 * 1.25 */
+ {0x30C9, 0x5E},
+ /* Timing Configuration */
+ {0x0202, 0x03},
+ {0x0203, 0x14},
+ {0x0204, 0x00},
+ {0x0205, 0x80},
+ {0x0340, 0x03},/* Frame Length */
+ {0x0341, 0xE0},
+ {0x0342, 0x0A},/* 2738 Line Length */
+ {0x0343, 0xB2},
+};
+
+static struct msm_camera_i2c_reg_conf s5k4e1_snap_settings[] = {
+ /*Output Size (2608x1960)*/
+ {0x30A9, 0x03},/* Horizontal Binning Off */
+ {0x300E, 0xE8},/* Vertical Binning Off */
+ {0x0387, 0x01},/* y_odd_inc */
+ {0x034C, 0x0A},/* x_output size */
+ {0x034D, 0x30},
+ {0x034E, 0x07},/* y_output size */
+ {0x034F, 0xA8},
+ {0x30BF, 0xAB},/* outif_enable[7], data_type[5:0](2Bh = bayer 10bit} */
+ {0x30C0, 0x80},/* video_offset[7:4] 3260%12 */
+ {0x30C8, 0x0C},/* video_data_length 3260 = 2608 * 1.25 */
+ {0x30C9, 0xBC},
+ /*Timing configuration*/
+ {0x0202, 0x06},
+ {0x0203, 0x28},
+ {0x0204, 0x00},
+ {0x0205, 0x80},
+ {0x0340, 0x07},/* Frame Length */
+ {0x0341, 0xB4},
+ {0x0342, 0x0A},/* 2738 Line Length */
+ {0x0343, 0xB2},
+};
+
+static struct msm_camera_i2c_reg_conf s5k4e1_recommend_settings[] = {
+ /* Reset setting */
+ {0x0103, 0x01},
+ /* MIPI settings */
+ {0x30BD, 0x00},/* SEL_CCP[0] */
+ {0x3084, 0x15},/* SYNC Mode */
+ {0x30BE, 0x1A},/* M_PCLKDIV_AUTO[4], M_DIV_PCLK[3:0] */
+ {0x30C1, 0x01},/* pack video enable [0] */
+ {0x30EE, 0x02},/* DPHY enable [ 1] */
+ {0x3111, 0x86},/* Embedded data off [5] */
+
+ /* REC Settings */
+ /*CDS timing setting ... */
+ {0x3000, 0x05},
+ {0x3001, 0x03},
+ {0x3002, 0x08},
+ {0x3003, 0x0A},
+ {0x3004, 0x50},
+ {0x3005, 0x0E},
+ {0x3006, 0x5E},
+ {0x3007, 0x00},
+ {0x3008, 0x78},
+ {0x3009, 0x78},
+ {0x300A, 0x50},
+ {0x300B, 0x08},
+ {0x300C, 0x14},
+ {0x300D, 0x00},
+ {0x300E, 0xE8},
+ {0x300F, 0x82},
+ {0x301B, 0x77},
+
+ /* CDS option setting ... */
+ {0x3010, 0x00},
+ {0x3011, 0x3A},
+ {0x3029, 0x04},
+ {0x3012, 0x30},
+ {0x3013, 0xA0},
+ {0x3014, 0x00},
+ {0x3015, 0x00},
+ {0x3016, 0x30},
+ {0x3017, 0x94},
+ {0x3018, 0x70},
+ {0x301D, 0xD4},
+ {0x3021, 0x02},
+ {0x3022, 0x24},
+ {0x3024, 0x40},
+ {0x3027, 0x08},
+
+ /* Pixel option setting ... */
+ {0x301C, 0x04},
+ {0x30D8, 0x3F},
+ {0x302B, 0x01},
+
+ {0x3070, 0x5F},
+ {0x3071, 0x00},
+ {0x3080, 0x04},
+ {0x3081, 0x38},
+
+ /* PLL settings */
+ {0x0305, 0x04},
+ {0x0306, 0x00},
+ {0x0307, 0x44},
+ {0x30B5, 0x00},
+ {0x30E2, 0x01},/* num lanes[1:0] = 2 */
+ {0x30F1, 0xB0},
+};
+
+static struct v4l2_subdev_info s5k4e1_subdev_info[] = {
+ {
+ .code = V4L2_MBUS_FMT_SGRBG10_1X10,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .fmt = 1,
+ .order = 0,
+ },
+ /* more can be supported, to be added later */
+};
+
+static struct msm_camera_i2c_conf_array s5k4e1_init_conf[] = {
+ {&s5k4e1_recommend_settings[0],
+ ARRAY_SIZE(s5k4e1_recommend_settings), 0, MSM_CAMERA_I2C_BYTE_DATA}
+};
+
+static struct msm_camera_i2c_conf_array s5k4e1_confs[] = {
+ {&s5k4e1_snap_settings[0],
+ ARRAY_SIZE(s5k4e1_snap_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+ {&s5k4e1_prev_settings[0],
+ ARRAY_SIZE(s5k4e1_prev_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+};
+
+static struct msm_sensor_output_info_t s5k4e1_dimensions[] = {
+ {
+ .x_output = 0xA30,
+ .y_output = 0x7A8,
+ .line_length_pclk = 0xAB2,
+ .frame_length_lines = 0x7B4,
+ .vt_pixel_clk = 816000000,
+ .op_pixel_clk = 816000000,
+ .binning_factor = 0,
+ },
+ {
+ .x_output = 0x518,
+ .y_output = 0x3D4,
+ .line_length_pclk = 0xAB2,
+ .frame_length_lines = 0x3E0,
+ .vt_pixel_clk = 816000000,
+ .op_pixel_clk = 816000000,
+ .binning_factor = 1,
+ },
+};
+
+static struct msm_camera_csi_params s5k4e1_csi_params = {
+ .data_format = CSI_10BIT,
+ .lane_cnt = 1,
+ .lane_assign = 0xe4,
+ .dpcm_scheme = 0,
+ .settle_cnt = 24,
+};
+
+static struct msm_camera_csi_params *s5k4e1_csi_params_array[] = {
+ &s5k4e1_csi_params,
+ &s5k4e1_csi_params,
+};
+
+static struct msm_sensor_output_reg_addr_t s5k4e1_reg_addr = {
+ .x_output = 0x034C,
+ .y_output = 0x034E,
+ .line_length_pclk = 0x0342,
+ .frame_length_lines = 0x0340,
+};
+
+static struct msm_sensor_id_info_t s5k4e1_id_info = {
+ .sensor_id_reg_addr = 0x0000,
+ .sensor_id = 0x4E10,
+};
+
+static struct msm_sensor_exp_gain_info_t s5k4e1_exp_gain_info = {
+ .coarse_int_time_addr = 0x0202,
+ .global_gain_addr = 0x0204,
+ .vert_offset = 4,
+};
+
+static inline uint8_t s5k4e1_byte(uint16_t word, uint8_t offset)
+{
+ return word >> (offset * BITS_PER_BYTE);
+}
+
+static int32_t s5k4e1_write_prev_exp_gain(struct msm_sensor_ctrl_t *s_ctrl,
+ uint16_t gain, uint32_t line)
+{
+ uint16_t max_legal_gain = 0x0200;
+ int32_t rc = 0;
+ static uint32_t fl_lines, offset;
+
+ pr_info("s5k4e1_write_prev_exp_gain :%d %d\n", gain, line);
+ offset = s_ctrl->sensor_exp_gain_info->vert_offset;
+ if (gain > max_legal_gain) {
+ CDBG("Max legal gain Line:%d\n", __LINE__);
+ gain = max_legal_gain;
+ }
+
+ /* Analogue Gain */
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->global_gain_addr,
+ s5k4e1_byte(gain, MSB),
+ MSM_CAMERA_I2C_BYTE_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->global_gain_addr + 1,
+ s5k4e1_byte(gain, LSB),
+ MSM_CAMERA_I2C_BYTE_DATA);
+
+ if (line > (s_ctrl->curr_frame_length_lines - offset)) {
+ fl_lines = line + offset;
+ s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_output_reg_addr->frame_length_lines,
+ s5k4e1_byte(fl_lines, MSB),
+ MSM_CAMERA_I2C_BYTE_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_output_reg_addr->frame_length_lines + 1,
+ s5k4e1_byte(fl_lines, LSB),
+ MSM_CAMERA_I2C_BYTE_DATA);
+ /* Coarse Integration Time */
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
+ s5k4e1_byte(line, MSB),
+ MSM_CAMERA_I2C_BYTE_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->coarse_int_time_addr + 1,
+ s5k4e1_byte(line, LSB),
+ MSM_CAMERA_I2C_BYTE_DATA);
+ s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
+ } else if (line < (fl_lines - offset)) {
+ fl_lines = line + offset;
+ if (fl_lines < s_ctrl->curr_frame_length_lines)
+ fl_lines = s_ctrl->curr_frame_length_lines;
+
+ s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
+ /* Coarse Integration Time */
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
+ s5k4e1_byte(line, MSB),
+ MSM_CAMERA_I2C_BYTE_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->coarse_int_time_addr + 1,
+ s5k4e1_byte(line, LSB),
+ MSM_CAMERA_I2C_BYTE_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_output_reg_addr->frame_length_lines,
+ s5k4e1_byte(fl_lines, MSB),
+ MSM_CAMERA_I2C_BYTE_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_output_reg_addr->frame_length_lines + 1,
+ s5k4e1_byte(fl_lines, LSB),
+ MSM_CAMERA_I2C_BYTE_DATA);
+ s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
+ } else {
+ fl_lines = line+4;
+ s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
+ /* Coarse Integration Time */
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
+ s5k4e1_byte(line, MSB),
+ MSM_CAMERA_I2C_BYTE_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->coarse_int_time_addr + 1,
+ s5k4e1_byte(line, LSB),
+ MSM_CAMERA_I2C_BYTE_DATA);
+ s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
+ }
+ return rc;
+}
+
+static int32_t s5k4e1_write_pict_exp_gain(struct msm_sensor_ctrl_t *s_ctrl,
+ uint16_t gain, uint32_t line)
+{
+ uint16_t max_legal_gain = 0x0200;
+ uint16_t min_ll_pck = 0x0AB2;
+ uint32_t ll_pck, fl_lines;
+ uint32_t ll_ratio;
+ uint8_t gain_msb, gain_lsb;
+ uint8_t intg_time_msb, intg_time_lsb;
+ uint8_t ll_pck_msb, ll_pck_lsb;
+
+ if (gain > max_legal_gain) {
+ CDBG("Max legal gain Line:%d\n", __LINE__);
+ gain = max_legal_gain;
+ }
+
+ gain = 32;
+ line = 1465;
+ pr_info("s5k4e1_write_exp_gain : gain = %d line = %d\n", gain, line);
+ line = (uint32_t) (line * s_ctrl->fps_divider);
+ fl_lines = s_ctrl->curr_frame_length_lines * s_ctrl->fps_divider / Q10;
+ ll_pck = s_ctrl->curr_line_length_pclk;
+
+ if (fl_lines < (line / Q10))
+ ll_ratio = (line / (fl_lines - 4));
+ else
+ ll_ratio = Q10;
+
+ ll_pck = ll_pck * ll_ratio / Q10;
+ line = line / ll_ratio;
+ if (ll_pck < min_ll_pck)
+ ll_pck = min_ll_pck;
+
+ gain_msb = (uint8_t) ((gain & 0xFF00) >> 8);
+ gain_lsb = (uint8_t) (gain & 0x00FF);
+
+ intg_time_msb = (uint8_t) ((line & 0xFF00) >> 8);
+ intg_time_lsb = (uint8_t) (line & 0x00FF);
+
+ ll_pck_msb = (uint8_t) ((ll_pck & 0xFF00) >> 8);
+ ll_pck_lsb = (uint8_t) (ll_pck & 0x00FF);
+
+ s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->global_gain_addr,
+ gain_msb,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->global_gain_addr + 1,
+ gain_lsb,
+ MSM_CAMERA_I2C_BYTE_DATA);
+
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_output_reg_addr->line_length_pclk,
+ ll_pck_msb,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_output_reg_addr->line_length_pclk + 1,
+ ll_pck_lsb,
+ MSM_CAMERA_I2C_BYTE_DATA);
+
+ /* Coarse Integration Time */
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
+ intg_time_msb,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->coarse_int_time_addr + 1,
+ intg_time_lsb,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
+
+ return 0;
+}
+
+static const struct i2c_device_id s5k4e1_i2c_id[] = {
+ {SENSOR_NAME, (kernel_ulong_t)&s5k4e1_s_ctrl},
+ { }
+};
+
+static struct i2c_driver s5k4e1_i2c_driver = {
+ .id_table = s5k4e1_i2c_id,
+ .probe = msm_sensor_i2c_probe,
+ .driver = {
+ .name = SENSOR_NAME,
+ },
+};
+
+static struct msm_camera_i2c_client s5k4e1_sensor_i2c_client = {
+ .addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static int __init msm_sensor_init_module(void)
+{
+ return i2c_add_driver(&s5k4e1_i2c_driver);
+}
+
+static struct v4l2_subdev_core_ops s5k4e1_subdev_core_ops = {
+ .ioctl = msm_sensor_subdev_ioctl,
+ .s_power = msm_sensor_power,
+};
+
+static struct v4l2_subdev_video_ops s5k4e1_subdev_video_ops = {
+ .enum_mbus_fmt = msm_sensor_v4l2_enum_fmt,
+};
+
+static struct v4l2_subdev_ops s5k4e1_subdev_ops = {
+ .core = &s5k4e1_subdev_core_ops,
+ .video = &s5k4e1_subdev_video_ops,
+};
+
+static struct msm_sensor_fn_t s5k4e1_func_tbl = {
+ .sensor_start_stream = msm_sensor_start_stream,
+ .sensor_stop_stream = msm_sensor_stop_stream,
+ .sensor_group_hold_on = msm_sensor_group_hold_on,
+ .sensor_group_hold_off = msm_sensor_group_hold_off,
+ .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_set_sensor_mode = msm_sensor_set_sensor_mode,
+ .sensor_mode_init = msm_sensor_mode_init,
+ .sensor_get_output_info = msm_sensor_get_output_info,
+ .sensor_config = msm_sensor_config,
+ .sensor_power_up = msm_sensor_power_up,
+ .sensor_power_down = msm_sensor_power_down,
+};
+
+static struct msm_sensor_reg_t s5k4e1_regs = {
+ .default_data_type = MSM_CAMERA_I2C_BYTE_DATA,
+ .start_stream_conf = s5k4e1_start_settings,
+ .start_stream_conf_size = ARRAY_SIZE(s5k4e1_start_settings),
+ .stop_stream_conf = s5k4e1_stop_settings,
+ .stop_stream_conf_size = ARRAY_SIZE(s5k4e1_stop_settings),
+ .group_hold_on_conf = s5k4e1_groupon_settings,
+ .group_hold_on_conf_size = ARRAY_SIZE(s5k4e1_groupon_settings),
+ .group_hold_off_conf = s5k4e1_groupoff_settings,
+ .group_hold_off_conf_size =
+ ARRAY_SIZE(s5k4e1_groupoff_settings),
+ .init_settings = &s5k4e1_init_conf[0],
+ .init_size = ARRAY_SIZE(s5k4e1_init_conf),
+ .mode_settings = &s5k4e1_confs[0],
+ .output_settings = &s5k4e1_dimensions[0],
+ .num_conf = ARRAY_SIZE(s5k4e1_confs),
+};
+
+static struct msm_sensor_ctrl_t s5k4e1_s_ctrl = {
+ .msm_sensor_reg = &s5k4e1_regs,
+ .sensor_i2c_client = &s5k4e1_sensor_i2c_client,
+ .sensor_i2c_addr = 0x6C,
+ .sensor_output_reg_addr = &s5k4e1_reg_addr,
+ .sensor_id_info = &s5k4e1_id_info,
+ .sensor_exp_gain_info = &s5k4e1_exp_gain_info,
+ .cam_mode = MSM_SENSOR_MODE_INVALID,
+ .csic_params = &s5k4e1_csi_params_array[0],
+ .msm_sensor_mutex = &s5k4e1_mut,
+ .sensor_i2c_driver = &s5k4e1_i2c_driver,
+ .sensor_v4l2_subdev_info = s5k4e1_subdev_info,
+ .sensor_v4l2_subdev_info_size = ARRAY_SIZE(s5k4e1_subdev_info),
+ .sensor_v4l2_subdev_ops = &s5k4e1_subdev_ops,
+ .func_tbl = &s5k4e1_func_tbl,
+};
+
+module_init(msm_sensor_init_module);
+MODULE_DESCRIPTION("Samsung 5MP Bayer sensor driver");
+MODULE_LICENSE("GPL v2");
+
+
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index fa30ef2..2c99a7f 100644
--- a/drivers/mfd/pm8921-core.c
+++ b/drivers/mfd/pm8921-core.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-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
@@ -42,6 +42,7 @@
#define PM8921_VERSION_MASK 0xFFF0
#define PM8921_VERSION_VALUE 0x06F0
#define PM8922_VERSION_VALUE 0x0AF0
+#define PM8917_VERSION_VALUE 0x12F0
#define PM8921_REVISION_MASK 0x000F
#define REG_PM8921_PON_CNTRL_3 0x01D
@@ -116,6 +117,9 @@
else if ((pmic->rev_registers & PM8921_VERSION_MASK)
== PM8922_VERSION_VALUE)
version = PM8XXX_VERSION_8922;
+ else if ((pmic->rev_registers & PM8921_VERSION_MASK)
+ == PM8917_VERSION_VALUE)
+ version = PM8XXX_VERSION_8917;
return version;
}
@@ -138,7 +142,7 @@
.pmic_get_revision = pm8921_get_revision,
};
-static const struct resource gpio_cell_resources[] __devinitconst = {
+static struct resource gpio_cell_resources[] = {
[0] = {
.start = PM8921_IRQ_BLOCK_BIT(PM8921_GPIO_BLOCK_START, 0),
.end = PM8921_IRQ_BLOCK_BIT(PM8921_GPIO_BLOCK_START, 0)
@@ -167,7 +171,7 @@
.num_resources = ARRAY_SIZE(adc_cell_resources),
};
-static const struct resource mpp_cell_resources[] __devinitconst = {
+static struct resource mpp_cell_resources[] = {
{
.start = PM8921_IRQ_BLOCK_BIT(PM8921_MPP_BLOCK_START, 0),
.end = PM8921_IRQ_BLOCK_BIT(PM8921_MPP_BLOCK_START, 0)
@@ -545,7 +549,14 @@
}
if (pdata->gpio_pdata) {
- pdata->gpio_pdata->gpio_cdata.ngpios = PM8921_NR_GPIOS;
+ if (version == PM8XXX_VERSION_8917) {
+ gpio_cell_resources[0].end = gpio_cell_resources[0].end
+ + PM8917_NR_GPIOS
+ - PM8921_NR_GPIOS;
+ pdata->gpio_pdata->gpio_cdata.ngpios = PM8917_NR_GPIOS;
+ } else {
+ pdata->gpio_pdata->gpio_cdata.ngpios = PM8921_NR_GPIOS;
+ }
gpio_cell.platform_data = pdata->gpio_pdata;
gpio_cell.pdata_size = sizeof(struct pm8xxx_gpio_platform_data);
ret = mfd_add_devices(pmic->dev, 0, &gpio_cell, 1,
@@ -557,7 +568,14 @@
}
if (pdata->mpp_pdata) {
- pdata->mpp_pdata->core_data.nmpps = PM8921_NR_MPPS;
+ if (version == PM8XXX_VERSION_8917) {
+ mpp_cell_resources[0].end = mpp_cell_resources[0].end
+ + PM8917_NR_MPPS
+ - PM8921_NR_MPPS;
+ pdata->mpp_pdata->core_data.nmpps = PM8917_NR_MPPS;
+ } else {
+ pdata->mpp_pdata->core_data.nmpps = PM8921_NR_MPPS;
+ }
pdata->mpp_pdata->core_data.base_addr = REG_MPP_BASE;
mpp_cell.platform_data = pdata->mpp_pdata;
mpp_cell.pdata_size = sizeof(struct pm8xxx_mpp_platform_data);
@@ -665,12 +683,6 @@
goto bail;
}
- ret = mfd_add_devices(pmic->dev, 0, &pwm_cell, 1, NULL, 0);
- if (ret) {
- pr_err("Failed to add pwm subdevice ret=%d\n", ret);
- goto bail;
- }
-
if (pdata->misc_pdata) {
misc_cell.platform_data = pdata->misc_pdata;
misc_cell.pdata_size = sizeof(struct pm8xxx_misc_platform_data);
@@ -682,16 +694,6 @@
}
}
- if (pdata->leds_pdata) {
- leds_cell.platform_data = pdata->leds_pdata;
- leds_cell.pdata_size = sizeof(struct pm8xxx_led_platform_data);
- ret = mfd_add_devices(pmic->dev, 0, &leds_cell, 1, NULL, 0);
- if (ret) {
- pr_err("Failed to add leds subdevice ret=%d\n", ret);
- goto bail;
- }
- }
-
ret = mfd_add_devices(pmic->dev, 0, &thermal_alarm_cell, 1, NULL,
irq_base);
if (ret) {
@@ -708,16 +710,37 @@
goto bail;
}
- if (pdata->vibrator_pdata) {
- vibrator_cell.platform_data = pdata->vibrator_pdata;
- vibrator_cell.pdata_size =
- sizeof(struct pm8xxx_vibrator_platform_data);
- ret = mfd_add_devices(pmic->dev, 0, &vibrator_cell, 1, NULL, 0);
+ if (version != PM8XXX_VERSION_8917) {
+ ret = mfd_add_devices(pmic->dev, 0, &pwm_cell, 1, NULL, 0);
if (ret) {
- pr_err("Failed to add vibrator subdevice ret=%d\n",
- ret);
+ pr_err("Failed to add pwm subdevice ret=%d\n", ret);
goto bail;
}
+
+ if (pdata->leds_pdata) {
+ leds_cell.platform_data = pdata->leds_pdata;
+ leds_cell.pdata_size =
+ sizeof(struct pm8xxx_led_platform_data);
+ ret = mfd_add_devices(pmic->dev, 0, &leds_cell,
+ 1, NULL, 0);
+ if (ret) {
+ pr_err("Failed to add leds subdevice ret=%d\n",
+ ret);
+ goto bail;
+ }
+ }
+
+ if (pdata->vibrator_pdata) {
+ vibrator_cell.platform_data = pdata->vibrator_pdata;
+ vibrator_cell.pdata_size =
+ sizeof(struct pm8xxx_vibrator_platform_data);
+ ret = mfd_add_devices(pmic->dev, 0, &vibrator_cell,
+ 1, NULL, 0);
+ if (ret) {
+ pr_err("Failed to add vibrator ret=%d\n", ret);
+ goto bail;
+ }
+ }
}
if (pdata->ccadc_pdata) {
@@ -768,6 +791,11 @@
[PM8XXX_REVISION_8922_2p0] = "2.0",
};
+static const char * const pm8917_rev_names[] = {
+ [PM8XXX_REVISION_8917_TEST] = "test",
+ [PM8XXX_REVISION_8917_1p0] = "1.0",
+};
+
static int __devinit pm8921_probe(struct platform_device *pdev)
{
const struct pm8921_platform_data *pdata = pdev->dev.platform_data;
@@ -823,9 +851,14 @@
if (revision >= 0 && revision < ARRAY_SIZE(pm8922_rev_names))
revision_name = pm8922_rev_names[revision];
pr_info("PMIC version: PM8922 rev %s\n", revision_name);
+ } else if (version == PM8XXX_VERSION_8917) {
+ if (revision >= 0 && revision < ARRAY_SIZE(pm8917_rev_names))
+ revision_name = pm8917_rev_names[revision];
+ pr_info("PMIC version: PM8917 rev %s\n", revision_name);
} else {
WARN_ON(version != PM8XXX_VERSION_8921
- && version != PM8XXX_VERSION_8922);
+ && version != PM8XXX_VERSION_8922
+ && version != PM8XXX_VERSION_8917);
}
/* Log human readable restart reason */
diff --git a/drivers/net/wireless/libra/qcomwlan_pwrif.c b/drivers/net/wireless/libra/qcomwlan_pwrif.c
index 6dd603c..8268f24 100644
--- a/drivers/net/wireless/libra/qcomwlan_pwrif.c
+++ b/drivers/net/wireless/libra/qcomwlan_pwrif.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* 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
@@ -69,6 +69,15 @@
1300000,
1250000,
};
+ static const int vregs_qwlan_peek_current[] = {
+ 4000,
+ 150000,
+ 200000,
+ 0,
+ 32000,
+ 130000,
+ 0,
+ };
static const bool vregs_is_pin_controlled_default[] = {
1,
1,
@@ -180,6 +189,15 @@
}
}
if (on && !wlan_on) {
+ if (vregs_qwlan_peek_current[i]) {
+ rc = regulator_set_optimum_mode(vregs_qwlan[i],
+ vregs_qwlan_peek_current[i]);
+ if (rc < 0)
+ pr_err("vreg %s set optimum mode"
+ " failed to %d (%d)\n",
+ vregs_qwlan_name[i], rc,
+ vregs_qwlan_peek_current[i]);
+ }
rc = regulator_enable(vregs_qwlan[i]);
if (rc < 0) {
pr_err("vreg %s enable failed (%d)\n",
@@ -195,6 +213,26 @@
}
}
} else if (!on && wlan_on) {
+
+ if (vregs_qwlan_peek_current[i]) {
+ /* For legacy reasons we pass 1mA current to
+ * put regulator in LPM mode.
+ */
+ rc = regulator_set_optimum_mode(vregs_qwlan[i],
+ 1000);
+ if (rc < 0)
+ pr_info("vreg %s set optimum mode"
+ "failed (%d)\n",
+ vregs_qwlan_name[i], rc);
+ rc = regulator_set_voltage(vregs_qwlan[i], 0 ,
+ vregs_qwlan_val_max[i]);
+ if (rc)
+ pr_err("regulator_set_voltage(%s)"
+ "failed (%d)\n",
+ vregs_qwlan_name[i], rc);
+
+ }
+
if (vregs_is_pin_controlled[i]) {
rc = regulator_disable(vregs_pc_qwlan[i]);
if (rc < 0) {
@@ -202,13 +240,16 @@
vregs_qwlan_pc_name[i], rc);
goto vreg_fail;
}
+ regulator_put(vregs_pc_qwlan[i]);
}
+
rc = regulator_disable(vregs_qwlan[i]);
if (rc < 0) {
pr_err("vreg %s disable failed (%d)\n",
vregs_qwlan_name[i], rc);
goto vreg_fail;
}
+ regulator_put(vregs_qwlan[i]);
}
}
if (on) {
diff --git a/drivers/net/wireless/wcnss/wcnss_riva.c b/drivers/net/wireless/wcnss/wcnss_riva.c
index fe6abf2..f6997ac 100644
--- a/drivers/net/wireless/wcnss/wcnss_riva.c
+++ b/drivers/net/wireless/wcnss/wcnss_riva.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-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
@@ -22,6 +22,7 @@
#include <linux/semaphore.h>
#include <linux/list.h>
#include <linux/slab.h>
+#include <linux/clk.h>
#include <mach/msm_xo.h>
#include <mach/msm_iomap.h>
@@ -79,10 +80,15 @@
};
-static int configure_iris_xo(bool use_48mhz_xo, int on)
+static int configure_iris_xo(struct device *dev, bool use_48mhz_xo, int on)
{
u32 reg = 0;
int rc = 0;
+ struct clk *cxo = clk_get(dev, "cxo");
+ if (IS_ERR(cxo)) {
+ pr_err("Couldn't get cxo clock\n");
+ return PTR_ERR(cxo);
+ }
if (on) {
msm_riva_base = ioremap(MSM_RIVA_PHYS, SZ_256);
@@ -92,6 +98,11 @@
}
/* Enable IRIS XO */
+ rc = clk_prepare_enable(cxo);
+ if (rc) {
+ pr_err("cxo enable failed\n");
+ goto fail;
+ }
writel_relaxed(0, RIVA_PMU_CFG);
reg = readl_relaxed(RIVA_PMU_CFG);
reg |= RIVA_PMU_CFG_GC_BUS_MUX_SEL_TOP |
@@ -119,6 +130,7 @@
reg &= ~(RIVA_PMU_CFG_GC_BUS_MUX_SEL_TOP |
RIVA_PMU_CFG_IRIS_XO_CFG);
writel_relaxed(reg, RIVA_PMU_CFG);
+ clk_disable_unprepare(cxo);
if (!use_48mhz_xo) {
wlan_clock = msm_xo_get(MSM_XO_TCXO_A2, id);
@@ -148,12 +160,14 @@
/* Add some delay for XO to settle */
msleep(20);
+ clk_put(cxo);
return rc;
msm_xo_vote_fail:
msm_xo_put(wlan_clock);
fail:
+ clk_put(cxo);
return rc;
}
@@ -302,13 +316,15 @@
goto fail_iris_on;
/* Configure IRIS XO */
- rc = configure_iris_xo(cfg->use_48mhz_xo, WCNSS_WLAN_SWITCH_ON);
+ rc = configure_iris_xo(dev, cfg->use_48mhz_xo,
+ WCNSS_WLAN_SWITCH_ON);
if (rc)
goto fail_iris_xo;
up(&riva_power_on_lock);
} else {
- configure_iris_xo(cfg->use_48mhz_xo, WCNSS_WLAN_SWITCH_OFF);
+ configure_iris_xo(dev, cfg->use_48mhz_xo,
+ WCNSS_WLAN_SWITCH_OFF);
wcnss_iris_vregs_off();
wcnss_riva_vregs_off();
}
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 787514c..3d739ae 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -2450,7 +2450,7 @@
goto free_regs;
}
- motg->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
+ motg->xo_handle = msm_xo_get(MSM_XO_CXO, "usb");
if (IS_ERR(motg->xo_handle)) {
dev_err(&pdev->dev, "%s not able to get the handle "
"to vote for TCXO D0 buffer\n", __func__);
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index 448194a..f261931 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -93,6 +93,10 @@
bool
default n
+config FB_MSM_LVDS
+ bool
+ default n
+
config FB_MSM_OVERLAY
depends on FB_MSM_MDP40 && ANDROID_PMEM
bool "MDP4 overlay support"
@@ -247,6 +251,11 @@
select FB_MSM_LCDC_PANEL
default n
+config FB_MSM_LVDS_CHIMEI_WXGA
+ bool
+ select FB_MSM_LVDS
+ default n
+
config FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT
bool
select FB_MSM_MIPI_DSI_TOSHIBA
@@ -389,6 +398,12 @@
---help---
Support for LCDC Samsung OLED PT (480x800) panel
+config FB_MSM_LVDS_CHIMEI_WXGA_PANEL
+ bool "LVDS Chimei WXGA Panel"
+ select FB_MSM_LVDS_CHIMEI_WXGA
+ ---help---
+ Support for LVDS Chimei WXGA(1366x768) panel
+
config FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
depends on FB_MSM_LCDC_HW
bool "MDDI Panel Auto Detect + LCDC Prism WVGA"
diff --git a/drivers/video/msm/Makefile b/drivers/video/msm/Makefile
index dc02da4..2d40b15 100644
--- a/drivers/video/msm/Makefile
+++ b/drivers/video/msm/Makefile
@@ -56,6 +56,9 @@
# LCDC
obj-$(CONFIG_FB_MSM_LCDC) += lcdc.o
+# LVDS
+obj-$(CONFIG_FB_MSM_LVDS) += lvds.o
+
# MDDI
msm_mddi-objs := mddi.o mddihost.o mddihosti.o
obj-$(CONFIG_FB_MSM_MDDI) += msm_mddi.o
@@ -143,6 +146,7 @@
obj-$(CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT) += lcdc_samsung_oled_pt.o
obj-$(CONFIG_FB_MSM_HDMI_ADV7520_PANEL) += adv7520.o
obj-$(CONFIG_FB_MSM_LCDC_ST15_WXGA) += lcdc_st15.o
+obj-$(CONFIG_FB_MSM_LVDS_CHIMEI_WXGA) += lvds_chimei_wxga.o
obj-$(CONFIG_FB_MSM_HDMI_MSM_PANEL) += hdmi_msm.o
obj-$(CONFIG_FB_MSM_EXT_INTERFACE_COMMON) += external_common.o
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index fc6054f..b5fcf0d 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -726,15 +726,6 @@
DEV_DBG("%s: ignored, probe failed\n", __func__);
return;
}
-#ifdef CONFIG_SUSPEND
- mutex_lock(&hdmi_msm_state_mutex);
- if (hdmi_msm_state->pm_suspended) {
- mutex_unlock(&hdmi_msm_state_mutex);
- DEV_WARN("%s: ignored, pm_suspended\n", __func__);
- return;
- }
- mutex_unlock(&hdmi_msm_state_mutex);
-#endif
DEV_DBG("%s:Got interrupt\n", __func__);
/* HPD_INT_STATUS[0x0250] */
@@ -839,15 +830,6 @@
static void hdcp_deauthenticate(void);
static void hdmi_msm_hdcp_reauth_work(struct work_struct *work)
{
-#ifdef CONFIG_SUSPEND
- mutex_lock(&hdmi_msm_state_mutex);
- if (hdmi_msm_state->pm_suspended) {
- mutex_unlock(&hdmi_msm_state_mutex);
- DEV_WARN("HDCP: deauthenticating skipped, pm_suspended\n");
- return;
- }
- mutex_unlock(&hdmi_msm_state_mutex);
-#endif
/* Don't process recursive actions */
mutex_lock(&hdmi_msm_state_mutex);
@@ -873,15 +855,6 @@
static void hdmi_msm_hdcp_work(struct work_struct *work)
{
-#ifdef CONFIG_SUSPEND
- mutex_lock(&hdmi_msm_state_mutex);
- if (hdmi_msm_state->pm_suspended) {
- mutex_unlock(&hdmi_msm_state_mutex);
- DEV_WARN("HDCP: Re-enable skipped, pm_suspended\n");
- return;
- }
- mutex_unlock(&hdmi_msm_state_mutex);
-#endif
/* Only re-enable if cable still connected */
mutex_lock(&external_common_state_hpd_mutex);
@@ -917,15 +890,6 @@
DEV_DBG("ISR ignored, probe failed\n");
return IRQ_HANDLED;
}
-#ifdef CONFIG_SUSPEND
- mutex_lock(&hdmi_msm_state_mutex);
- if (hdmi_msm_state->pm_suspended) {
- mutex_unlock(&hdmi_msm_state_mutex);
- DEV_WARN("ISR ignored, pm_suspended\n");
- return IRQ_HANDLED;
- }
- mutex_unlock(&hdmi_msm_state_mutex);
-#endif
/* Process HPD Interrupt */
/* HDMI_HPD_INT_STATUS[0x0250] */
@@ -3956,7 +3920,6 @@
disable_irq(hdmi_msm_state->irq);
hdmi_msm_set_mode(FALSE);
- HDMI_OUTP_ND(0x0308, 0x7F); /*0b01111111*/
hdmi_msm_state->hpd_initialized = FALSE;
hdmi_msm_state->pd->cec_power(0);
hdmi_msm_state->pd->enable_5v(0);
@@ -4035,15 +3998,6 @@
if (!hdmi_msm_state || !hdmi_msm_state->hdmi_app_clk || !MSM_HDMI_BASE)
return -ENODEV;
-#ifdef CONFIG_SUSPEND
- mutex_lock(&hdmi_msm_state_mutex);
- if (hdmi_msm_state->pm_suspended) {
- mutex_unlock(&hdmi_msm_state_mutex);
- DEV_WARN("%s: ignored, pm_suspended\n", __func__);
- return -ENODEV;
- }
- mutex_unlock(&hdmi_msm_state_mutex);
-#endif
DEV_INFO("power: ON (%dx%d %d)\n", mfd->var_xres, mfd->var_yres,
mfd->var_pixclock);
@@ -4095,15 +4049,6 @@
{
if (!hdmi_msm_state->hdmi_app_clk)
return -ENODEV;
-#ifdef CONFIG_SUSPEND
- mutex_lock(&hdmi_msm_state_mutex);
- if (hdmi_msm_state->pm_suspended) {
- mutex_unlock(&hdmi_msm_state_mutex);
- DEV_WARN("%s: ignored, pm_suspended\n", __func__);
- return -ENODEV;
- }
- mutex_unlock(&hdmi_msm_state_mutex);
-#endif
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
mutex_lock(&hdmi_msm_state_mutex);
@@ -4369,71 +4314,10 @@
return rc;
}
-
-#ifdef CONFIG_SUSPEND
-static int hdmi_msm_device_pm_suspend(struct device *dev)
-{
- mutex_lock(&hdmi_msm_state_mutex);
- if (hdmi_msm_state->pm_suspended) {
- mutex_unlock(&hdmi_msm_state_mutex);
- return 0;
- }
-
- DEV_DBG("pm_suspend\n");
-
- del_timer(&hdmi_msm_state->hpd_state_timer);
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
- del_timer(&hdmi_msm_state->hdcp_timer);
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
-
- disable_irq(hdmi_msm_state->irq);
- if (external_common_state->hpd_feature_on)
- hdmi_msm_clk(0);
-
- hdmi_msm_state->pm_suspended = TRUE;
- mutex_unlock(&hdmi_msm_state_mutex);
-
- hdmi_msm_powerdown_phy();
- hdmi_msm_state->pd->enable_5v(0);
- hdmi_msm_state->pd->core_power(0, 1);
- return 0;
-}
-
-static int hdmi_msm_device_pm_resume(struct device *dev)
-{
- mutex_lock(&hdmi_msm_state_mutex);
- if (!hdmi_msm_state->pm_suspended) {
- mutex_unlock(&hdmi_msm_state_mutex);
- return 0;
- }
-
- DEV_DBG("pm_resume\n");
-
- hdmi_msm_state->pd->core_power(1, 1);
- hdmi_msm_state->pd->enable_5v(1);
- if (external_common_state->hpd_feature_on)
- hdmi_msm_clk(1);
-
- hdmi_msm_state->pm_suspended = FALSE;
- mutex_unlock(&hdmi_msm_state_mutex);
- enable_irq(hdmi_msm_state->irq);
- return 0;
-}
-#else
-#define hdmi_msm_device_pm_suspend NULL
-#define hdmi_msm_device_pm_resume NULL
-#endif
-
-static const struct dev_pm_ops hdmi_msm_device_pm_ops = {
- .suspend = hdmi_msm_device_pm_suspend,
- .resume = hdmi_msm_device_pm_resume,
-};
-
static struct platform_driver this_driver = {
.probe = hdmi_msm_probe,
.remove = hdmi_msm_remove,
.driver.name = "hdmi_msm",
- .driver.pm = &hdmi_msm_device_pm_ops,
};
static struct msm_fb_panel_data hdmi_msm_panel_data = {
diff --git a/drivers/video/msm/lvds.c b/drivers/video/msm/lvds.c
new file mode 100644
index 0000000..7ef437c
--- /dev/null
+++ b/drivers/video/msm/lvds.c
@@ -0,0 +1,235 @@
+/* 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/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <mach/clk.h>
+
+#include "msm_fb.h"
+
+static int lvds_probe(struct platform_device *pdev);
+static int lvds_remove(struct platform_device *pdev);
+
+static int lvds_off(struct platform_device *pdev);
+static int lvds_on(struct platform_device *pdev);
+
+static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
+static int pdev_list_cnt;
+
+static struct clk *lvds_clk;
+
+static struct platform_driver lvds_driver = {
+ .probe = lvds_probe,
+ .remove = lvds_remove,
+ .suspend = NULL,
+ .resume = NULL,
+ .shutdown = NULL,
+ .driver = {
+ .name = "lvds",
+ },
+};
+
+static struct lcdc_platform_data *lvds_pdata;
+
+static int lvds_off(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct msm_fb_data_type *mfd;
+
+ mfd = platform_get_drvdata(pdev);
+ ret = panel_next_off(pdev);
+
+ clk_disable(lvds_clk);
+
+ if (lvds_pdata && lvds_pdata->lcdc_power_save)
+ lvds_pdata->lcdc_power_save(0);
+
+ if (lvds_pdata && lvds_pdata->lcdc_gpio_config)
+ ret = lvds_pdata->lcdc_gpio_config(0);
+
+#ifdef CONFIG_MSM_BUS_SCALING
+ mdp_bus_scale_update_request(0);
+#endif
+
+ return ret;
+}
+
+static int lvds_on(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct msm_fb_data_type *mfd;
+ unsigned long panel_pixclock_freq = 0;
+ mfd = platform_get_drvdata(pdev);
+
+ if (lvds_pdata && lvds_pdata->lcdc_get_clk)
+ panel_pixclock_freq = lvds_pdata->lcdc_get_clk();
+
+ if (!panel_pixclock_freq)
+ panel_pixclock_freq = mfd->fbi->var.pixclock;
+#ifdef CONFIG_MSM_BUS_SCALING
+ mdp_bus_scale_update_request(2);
+#endif
+ mfd = platform_get_drvdata(pdev);
+
+ mfd->fbi->var.pixclock = clk_round_rate(lvds_clk,
+ mfd->fbi->var.pixclock);
+ ret = clk_set_rate(lvds_clk, mfd->fbi->var.pixclock);
+ if (ret) {
+ pr_err("%s: Can't set lvds clock to rate %u\n",
+ __func__, mfd->fbi->var.pixclock);
+ goto out;
+ }
+
+ clk_enable(lvds_clk);
+
+ if (lvds_pdata && lvds_pdata->lcdc_power_save)
+ lvds_pdata->lcdc_power_save(1);
+ if (lvds_pdata && lvds_pdata->lcdc_gpio_config)
+ ret = lvds_pdata->lcdc_gpio_config(1);
+
+ ret = panel_next_on(pdev);
+
+out:
+ return ret;
+}
+
+static int lvds_probe(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+ struct fb_info *fbi;
+ struct platform_device *mdp_dev = NULL;
+ struct msm_fb_panel_data *pdata = NULL;
+ int rc;
+
+ if (pdev->id == 0) {
+ lvds_pdata = pdev->dev.platform_data;
+ return 0;
+ }
+
+ mfd = platform_get_drvdata(pdev);
+
+ if (!mfd)
+ return -ENODEV;
+
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
+ return -ENOMEM;
+
+ mdp_dev = platform_device_alloc("mdp", pdev->id);
+ if (!mdp_dev)
+ return -ENOMEM;
+
+ /*
+ * link to the latest pdev
+ */
+ mfd->pdev = mdp_dev;
+ mfd->dest = DISPLAY_LCDC;
+
+ /*
+ * alloc panel device data
+ */
+ if (platform_device_add_data
+ (mdp_dev, pdev->dev.platform_data,
+ sizeof(struct msm_fb_panel_data))) {
+ pr_err("lvds_probe: platform_device_add_data failed!\n");
+ platform_device_put(mdp_dev);
+ return -ENOMEM;
+ }
+ /*
+ * data chain
+ */
+ pdata = (struct msm_fb_panel_data *)mdp_dev->dev.platform_data;
+ pdata->on = lvds_on;
+ pdata->off = lvds_off;
+ pdata->next = pdev;
+
+ /*
+ * get/set panel specific fb info
+ */
+ mfd->panel_info = pdata->panel_info;
+
+ if (mfd->index == 0)
+ mfd->fb_imgType = MSMFB_DEFAULT_TYPE;
+ else
+ mfd->fb_imgType = MDP_RGB_565;
+
+ fbi = mfd->fbi;
+ fbi->var.pixclock = clk_round_rate(lvds_clk,
+ mfd->panel_info.clk_rate);
+ fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch;
+ fbi->var.right_margin = mfd->panel_info.lcdc.h_front_porch;
+ fbi->var.upper_margin = mfd->panel_info.lcdc.v_back_porch;
+ fbi->var.lower_margin = mfd->panel_info.lcdc.v_front_porch;
+ fbi->var.hsync_len = mfd->panel_info.lcdc.h_pulse_width;
+ fbi->var.vsync_len = mfd->panel_info.lcdc.v_pulse_width;
+
+ /*
+ * set driver data
+ */
+ platform_set_drvdata(mdp_dev, mfd);
+ /*
+ * register in mdp driver
+ */
+ rc = platform_device_add(mdp_dev);
+ if (rc)
+ goto lvds_probe_err;
+
+ pdev_list[pdev_list_cnt++] = pdev;
+
+ return 0;
+
+lvds_probe_err:
+ platform_device_put(mdp_dev);
+ return rc;
+}
+
+static int lvds_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int lvds_register_driver(void)
+{
+ return platform_driver_register(&lvds_driver);
+}
+
+static int __init lvds_driver_init(void)
+{
+ lvds_clk = clk_get(NULL, "lvds_clk");
+ if (IS_ERR(lvds_clk)) {
+ pr_err("Couldnt find lvds_clk\n");
+ return -EINVAL;
+ }
+
+ return lvds_register_driver();
+}
+
+module_init(lvds_driver_init);
diff --git a/drivers/video/msm/lvds_chimei_wxga.c b/drivers/video/msm/lvds_chimei_wxga.c
new file mode 100644
index 0000000..2c6b6d4
--- /dev/null
+++ b/drivers/video/msm/lvds_chimei_wxga.c
@@ -0,0 +1,124 @@
+/* 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 "msm_fb.h"
+
+static struct msm_panel_common_pdata *cm_pdata;
+static struct platform_device *cm_fbpdev;
+
+static int lvds_chimei_panel_on(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int lvds_chimei_panel_off(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static void lvds_chimei_set_backlight(struct msm_fb_data_type *mfd)
+{
+}
+
+static int __devinit lvds_chimei_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+
+ if (pdev->id == 0) {
+ cm_pdata = pdev->dev.platform_data;
+ if (cm_pdata == NULL)
+ pr_err("%s: no PWM gpio specified\n", __func__);
+ return 0;
+ }
+
+ cm_fbpdev = msm_fb_add_device(pdev);
+ if (!cm_fbpdev) {
+ dev_err(&pdev->dev, "failed to add msm_fb device\n");
+ rc = -ENODEV;
+ goto probe_exit;
+ }
+
+probe_exit:
+ return rc;
+}
+
+static struct platform_driver this_driver = {
+ .probe = lvds_chimei_probe,
+ .driver = {
+ .name = "lvds_chimei_wxga",
+ },
+};
+
+static struct msm_fb_panel_data lvds_chimei_panel_data = {
+ .on = lvds_chimei_panel_on,
+ .off = lvds_chimei_panel_off,
+ .set_backlight = lvds_chimei_set_backlight,
+};
+
+static struct platform_device this_device = {
+ .name = "lvds_chimei_wxga",
+ .id = 1,
+ .dev = {
+ .platform_data = &lvds_chimei_panel_data,
+ }
+};
+
+static int __init lvds_chimei_wxga_init(void)
+{
+ int ret;
+ struct msm_panel_info *pinfo;
+
+ if (msm_fb_detect_client("lvds_chimei_wxga"))
+ return 0;
+
+ ret = platform_driver_register(&this_driver);
+ if (ret)
+ return ret;
+
+ pinfo = &lvds_chimei_panel_data.panel_info;
+ pinfo->xres = 320;
+ pinfo->yres = 240;
+ MSM_FB_SINGLE_MODE_PANEL(pinfo);
+ pinfo->type = LVDS_PANEL;
+ pinfo->pdest = DISPLAY_1;
+ pinfo->wait_cycle = 0;
+ pinfo->bpp = 24;
+ pinfo->fb_num = 2;
+ pinfo->clk_rate = 75000000;
+ pinfo->bl_max = 15;
+ pinfo->bl_min = 1;
+
+ /*
+ * this panel is operated by de,
+ * vsycn and hsync are ignored
+ */
+ pinfo->lcdc.h_back_porch = 0;
+ pinfo->lcdc.h_front_porch = 194;
+ pinfo->lcdc.h_pulse_width = 40;
+ pinfo->lcdc.v_back_porch = 0;
+ pinfo->lcdc.v_front_porch = 38;
+ pinfo->lcdc.v_pulse_width = 20;
+ pinfo->lcdc.border_clr = 0xffff00;
+ pinfo->lcdc.underflow_clr = 0xff;
+ pinfo->lcdc.hsync_skew = 0;
+ pinfo->lvds.channel_mode = LVDS_SINGLE_CHANNEL_MODE;
+ pinfo->lcdc.xres_pad = 1046;
+ pinfo->lcdc.yres_pad = 528;
+
+ ret = platform_device_register(&this_device);
+ if (ret)
+ platform_driver_unregister(&this_driver);
+
+ return ret;
+}
+
+module_init(lvds_chimei_wxga_init);
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index b39e81c..f27bd49 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -1562,6 +1562,7 @@
#endif
case HDMI_PANEL:
case LCDC_PANEL:
+ case LVDS_PANEL:
pdata->on = mdp_lcdc_on;
pdata->off = mdp_lcdc_off;
mfd->hw_refresh = TRUE;
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 88582e4..5f5d632 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -188,9 +188,9 @@
dsi_underflow_clr = mfd->panel_info.lcdc.underflow_clr;
dsi_hsync_skew = mfd->panel_info.lcdc.hsync_skew;
dsi_width = mfd->panel_info.xres +
- mfd->panel_info.mipi.xres_pad;
+ mfd->panel_info.lcdc.xres_pad;
dsi_height = mfd->panel_info.yres +
- mfd->panel_info.mipi.yres_pad;
+ mfd->panel_info.lcdc.yres_pad;
dsi_bpp = mfd->panel_info.bpp;
hsync_period = hsync_pulse_width + h_back_porch + dsi_width
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index 5ad6de3f..ebde23b 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -45,6 +45,73 @@
static struct mdp4_overlay_pipe *lcdc_pipe;
static struct completion lcdc_comp;
+static void lvds_init(struct msm_fb_data_type *mfd)
+{
+ unsigned int lvds_intf, lvds_phy_cfg0;
+
+ if (mfd->panel_info.bpp == 24) {
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */
+ MDP_OUTP(MDP_BASE + 0xc2014, 0x03040508);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */
+ MDP_OUTP(MDP_BASE + 0xc2018, 0x00000102);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */
+ MDP_OUTP(MDP_BASE + 0xc201c, 0x0c0d1011);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */
+ MDP_OUTP(MDP_BASE + 0xc2020, 0x00090a0b);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */
+ MDP_OUTP(MDP_BASE + 0xc2024, 0x1518191a);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
+ MDP_OUTP(MDP_BASE + 0xc2028, 0x00121314);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_3_TO_0 */
+ MDP_OUTP(MDP_BASE + 0xc202c, 0x0f16171b);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_6_TO_4 */
+ MDP_OUTP(MDP_BASE + 0xc2030, 0x0006070e);
+
+ if (mfd->panel_info.lvds.channel_mode ==
+ LVDS_DUAL_CHANNEL_MODE) {
+ lvds_intf = 0x0001ff80;
+ lvds_phy_cfg0 = BIT(6) | BIT(7);
+ if (mfd->panel_info.lvds.channel_swap)
+ lvds_intf |= BIT(4);
+ } else {
+ lvds_intf = 0x00010f84;
+ lvds_phy_cfg0 = BIT(6);
+ }
+ } else if (mfd->panel_info.bpp == 18) {
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */
+ MDP_OUTP(MDP_BASE + 0xc2014, 0x03040508);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */
+ MDP_OUTP(MDP_BASE + 0xc2018, 0x00000102);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */
+ MDP_OUTP(MDP_BASE + 0xc201c, 0x0c0d1011);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */
+ MDP_OUTP(MDP_BASE + 0xc2020, 0x00090a0b);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */
+ MDP_OUTP(MDP_BASE + 0xc2024, 0x1518191a);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
+ MDP_OUTP(MDP_BASE + 0xc2028, 0x00121314);
+
+ if (mfd->panel_info.lvds.channel_mode ==
+ LVDS_DUAL_CHANNEL_MODE) {
+ lvds_intf = 0x00017788;
+ lvds_phy_cfg0 = BIT(6) | BIT(7);
+ if (mfd->panel_info.lvds.channel_swap)
+ lvds_intf |= BIT(4);
+ } else {
+ lvds_intf = 0x0001078c;
+ lvds_phy_cfg0 = BIT(6);
+ }
+ }
+
+ /* MDP_LVDSPHY_CFG0 */
+ MDP_OUTP(MDP_BASE + 0xc3100, lvds_phy_cfg0);
+ /* MDP_LCDC_LVDS_INTF_CTL */
+ MDP_OUTP(MDP_BASE + 0xc2000, lvds_intf);
+ lvds_phy_cfg0 |= BIT(4);
+ /* MDP_LVDSPHY_CFG0, enable serialization */
+ MDP_OUTP(MDP_BASE + 0xc3100, lvds_phy_cfg0);
+}
+
int mdp_lcdc_on(struct platform_device *pdev)
{
int lcdc_width;
@@ -165,8 +232,8 @@
lcdc_underflow_clr = mfd->panel_info.lcdc.underflow_clr;
lcdc_hsync_skew = mfd->panel_info.lcdc.hsync_skew;
- lcdc_width = var->xres;
- lcdc_height = var->yres;
+ lcdc_width = var->xres + mfd->panel_info.lcdc.xres_pad;
+ lcdc_height = var->yres + mfd->panel_info.lcdc.yres_pad;
lcdc_bpp = mfd->panel_info.bpp;
hsync_period =
@@ -237,6 +304,9 @@
#endif
mdp_histogram_ctrl(TRUE);
+ if (mfd->panel.type == LVDS_PANEL)
+ lvds_init(mfd);
+
ret = panel_next_on(pdev);
if (ret == 0) {
/* enable LCDC block */
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index 40056f0..a4a5b06 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -2556,23 +2556,23 @@
return 0;
if (!buf->size) {
- pr_err("%s:%d In valid size", __func__, __LINE__);
+ pr_err("%s:%d In valid size\n", __func__, __LINE__);
return -EINVAL;
}
if (!IS_ERR_OR_NULL(mfd->iclient)) {
- pr_info("%s:%d ion based allocation", __func__, __LINE__);
+ pr_info("%s:%d ion based allocation\n", __func__, __LINE__);
buf->ihdl = ion_alloc(mfd->iclient, buf->size, 4,
(1 << mfd->mem_hid));
if (!IS_ERR_OR_NULL(buf->ihdl)) {
if (ion_phys(mfd->iclient, buf->ihdl,
&addr, &len)) {
- pr_err("%s:%d: ion_phys map failed",
+ pr_err("%s:%d: ion_phys map failed\n",
__func__, __LINE__);
return -ENOMEM;
}
} else {
- pr_err("%s:%d: ion_alloc failed", __func__,
+ pr_err("%s:%d: ion_alloc failed\n", __func__,
__LINE__);
return -ENOMEM;
}
@@ -2602,14 +2602,18 @@
buf = mfd->ov1_wb_buf;
if (!IS_ERR_OR_NULL(mfd->iclient)) {
- if (!IS_ERR_OR_NULL(buf->ihdl))
+ if (!IS_ERR_OR_NULL(buf->ihdl)) {
ion_free(mfd->iclient, buf->ihdl);
- buf->ihdl = NULL;
- pr_info("%s:%d free writeback imem", __func__, __LINE__);
+ pr_info("%s:%d free writeback imem\n", __func__,
+ __LINE__);
+ buf->ihdl = NULL;
+ }
} else {
- if (buf->phys_addr)
+ if (buf->phys_addr) {
free_contiguous_memory_by_paddr(buf->phys_addr);
- pr_info("%s:%d free writeback pmem", __func__, __LINE__);
+ pr_info("%s:%d free writeback pmem\n", __func__,
+ __LINE__);
+ }
}
buf->phys_addr = 0;
}
diff --git a/drivers/video/msm/mdp4_wfd_writeback_panel.c b/drivers/video/msm/mdp4_wfd_writeback_panel.c
index 32b0669..40ffb65 100644
--- a/drivers/video/msm/mdp4_wfd_writeback_panel.c
+++ b/drivers/video/msm/mdp4_wfd_writeback_panel.c
@@ -37,8 +37,8 @@
static struct msm_fb_panel_data writeback_msm_panel_data = {
.panel_info = {
.type = WRITEBACK_PANEL,
- .xres = 800,
- .yres = 480,
+ .xres = 1280,
+ .yres = 720,
.pdest = DISPLAY_3,
.wait_cycle = 0,
.bpp = 24,
diff --git a/drivers/video/msm/mipi_dsi.c b/drivers/video/msm/mipi_dsi.c
index aa210f1..f319072 100644
--- a/drivers/video/msm/mipi_dsi.c
+++ b/drivers/video/msm/mipi_dsi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-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
@@ -196,8 +196,8 @@
mipi = &mfd->panel_info.mipi;
if (mfd->panel_info.type == MIPI_VIDEO_PANEL) {
- dummy_xres = mfd->panel_info.mipi.xres_pad;
- dummy_yres = mfd->panel_info.mipi.yres_pad;
+ dummy_xres = mfd->panel_info.lcdc.xres_pad;
+ dummy_yres = mfd->panel_info.lcdc.yres_pad;
if (mdp_rev >= MDP_REV_41) {
MIPI_OUTP(MIPI_DSI_BASE + 0x20,
@@ -539,8 +539,8 @@
if (mfd->panel_info.type == MIPI_VIDEO_PANEL &&
!mfd->panel_info.clk_rate) {
- h_period += mfd->panel_info.mipi.xres_pad;
- v_period += mfd->panel_info.mipi.yres_pad;
+ h_period += mfd->panel_info.lcdc.xres_pad;
+ v_period += mfd->panel_info.lcdc.yres_pad;
if (lanes > 0) {
mfd->panel_info.clk_rate =
diff --git a/drivers/video/msm/mipi_toshiba_video_wsvga_pt.c b/drivers/video/msm/mipi_toshiba_video_wsvga_pt.c
index 2c02490..48bdb1d 100644
--- a/drivers/video/msm/mipi_toshiba_video_wsvga_pt.c
+++ b/drivers/video/msm/mipi_toshiba_video_wsvga_pt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-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
@@ -49,8 +49,8 @@
* include dummy(pad) data of 200 clk in addition to
* width and porch/sync width values
*/
- pinfo.mipi.xres_pad = 200;
- pinfo.mipi.yres_pad = 0;
+ pinfo.lcdc.xres_pad = 200;
+ pinfo.lcdc.yres_pad = 0;
pinfo.type = MIPI_VIDEO_PANEL;
pinfo.pdest = DISPLAY_1;
diff --git a/drivers/video/msm/msm_dss_io_8960.c b/drivers/video/msm/msm_dss_io_8960.c
index 52a10ab..3b000ec 100644
--- a/drivers/video/msm/msm_dss_io_8960.c
+++ b/drivers/video/msm/msm_dss_io_8960.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-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
@@ -643,9 +643,6 @@
HDMI_OUTP(HDMI_PHY_REG_0, 0x1B);
HDMI_OUTP(HDMI_PHY_REG_1, 0xf2);
- HDMI_OUTP(HDMI_PHY_REG_2, 0x7F);
- HDMI_OUTP(HDMI_PHY_REG_2, 0x3F);
- HDMI_OUTP(HDMI_PHY_REG_2, 0x1F);
offset = HDMI_PHY_REG_4;
while (offset <= HDMI_PHY_REG_11) {
@@ -653,12 +650,7 @@
offset += 0x4;
}
- HDMI_OUTP(HDMI_PHY_REG_12, HDMI_INP(HDMI_PHY_REG_12) | PWRDN_B);
- msleep(100);
-
HDMI_OUTP(HDMI_PHY_REG_3, 0x20);
- HDMI_OUTP(HDMI_PHY_REG_12, 0x81);
- HDMI_OUTP(HDMI_PHY_REG_2, 0x81);
}
void hdmi_msm_powerdown_phy(void)
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 89ccbb9..bdfadd5 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -270,6 +270,9 @@
case HDMI_PANEL:
ret = snprintf(buf, PAGE_SIZE, "hdmi panel\n");
break;
+ case LVDS_PANEL:
+ ret = snprintf(buf, PAGE_SIZE, "lvds panel\n");
+ break;
case DTV_PANEL:
ret = snprintf(buf, PAGE_SIZE, "dtv panel\n");
break;
@@ -603,10 +606,42 @@
return 0;
}
+static int msm_fb_ext_suspend(struct device *dev)
+{
+ struct msm_fb_data_type *mfd = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if ((!mfd) || (mfd->key != MFD_KEY))
+ return 0;
+
+ if (mfd->panel_info.type == HDMI_PANEL ||
+ mfd->panel_info.type == DTV_PANEL)
+ ret = msm_fb_suspend_sub(mfd);
+
+ return ret;
+}
+
+static int msm_fb_ext_resume(struct device *dev)
+{
+ struct msm_fb_data_type *mfd = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if ((!mfd) || (mfd->key != MFD_KEY))
+ return 0;
+
+ if (mfd->panel_info.type == HDMI_PANEL ||
+ mfd->panel_info.type == DTV_PANEL)
+ ret = msm_fb_resume_sub(mfd);
+
+ return ret;
+}
+
static struct dev_pm_ops msm_fb_dev_pm_ops = {
.runtime_suspend = msm_fb_runtime_suspend,
.runtime_resume = msm_fb_runtime_resume,
.runtime_idle = msm_fb_runtime_idle,
+ .suspend = msm_fb_ext_suspend,
+ .resume = msm_fb_ext_resume,
};
static struct platform_driver msm_fb_driver = {
diff --git a/drivers/video/msm/msm_fb_panel.c b/drivers/video/msm/msm_fb_panel.c
index d8eaea2..8640116 100644
--- a/drivers/video/msm/msm_fb_panel.c
+++ b/drivers/video/msm/msm_fb_panel.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-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
@@ -106,6 +106,10 @@
snprintf(dev_name, sizeof(dev_name), "lcdc");
break;
+ case LVDS_PANEL:
+ snprintf(dev_name, sizeof(dev_name), "lvds");
+ break;
+
case DTV_PANEL:
snprintf(dev_name, sizeof(dev_name), "dtv");
break;
diff --git a/drivers/video/msm/msm_fb_panel.h b/drivers/video/msm/msm_fb_panel.h
index d66d802..903c865 100644
--- a/drivers/video/msm/msm_fb_panel.h
+++ b/drivers/video/msm/msm_fb_panel.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-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
@@ -38,6 +38,7 @@
#define MIPI_VIDEO_PANEL 8 /* MIPI */
#define MIPI_CMD_PANEL 9 /* MIPI */
#define WRITEBACK_PANEL 10 /* Wifi display */
+#define LVDS_PANEL 11 /* LVDS */
/* panel class */
typedef enum {
@@ -77,6 +78,10 @@
__u32 border_clr;
__u32 underflow_clr;
__u32 hsync_skew;
+ /* Pad width */
+ uint32 xres_pad;
+ /* Pad height */
+ uint32 yres_pad;
};
struct mddi_panel_info {
@@ -127,10 +132,17 @@
char no_max_pkt_size;
/* Clock required during LP commands */
char force_clk_lane_hs;
- /* Pad width */
- uint32 xres_pad;
- /* Pad height */
- uint32 yres_pad;
+};
+
+enum lvds_mode {
+ LVDS_SINGLE_CHANNEL_MODE,
+ LVDS_DUAL_CHANNEL_MODE,
+};
+
+struct lvds_panel_info {
+ enum lvds_mode channel_mode;
+ /* Channel swap in dual mode */
+ char channel_swap;
};
struct msm_panel_info {
@@ -156,8 +168,8 @@
struct mddi_panel_info mddi;
struct lcd_panel_info lcd;
struct lcdc_panel_info lcdc;
-
struct mipi_panel_info mipi;
+ struct lvds_panel_info lvds;
};
#define MSM_FB_SINGLE_MODE_PANEL(pinfo) \
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index 980ec21..8a2f534 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -804,6 +804,7 @@
u32 len = 0, flags = 0;
struct file *file;
int rc = 0;
+ unsigned long ionflag;
if (!client_ctx || !mv_data)
return false;
@@ -838,10 +839,18 @@
ERR("%s(): get_ION_handle failed\n", __func__);
goto ion_error;
}
+ rc = ion_handle_get_flags(client_ctx->user_ion_client,
+ client_ctx->h264_mv_ion_handle,
+ &ionflag);
+ if (rc) {
+ ERR("%s():get_ION_flags fail\n",
+ __func__);
+ goto ion_error;
+ }
vcd_h264_mv_buffer->kernel_virtual_addr = (u8 *) ion_map_kernel(
client_ctx->user_ion_client,
client_ctx->h264_mv_ion_handle,
- 0);
+ ionflag);
if (!vcd_h264_mv_buffer->kernel_virtual_addr) {
ERR("%s(): get_ION_kernel virtual addr failed\n",
__func__);
@@ -1651,6 +1660,7 @@
{
struct vdec_seqheader seq_header;
struct vcd_sequence_hdr vcd_seq_hdr;
+ unsigned long ionflag;
DBG("VDEC_IOCTL_SET_SEQUENCE_HEADER\n");
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg))) {
ERR("Copy from user vdec_msg failed\n");
@@ -1681,9 +1691,19 @@
ERR("%s(): get_ION_handle failed\n", __func__);
return false;
}
+ rc = ion_handle_get_flags(client_ctx->user_ion_client,
+ client_ctx->seq_hdr_ion_handle,
+ &ionflag);
+ if (rc) {
+ ERR("%s():get_ION_flags fail\n",
+ __func__);
+ ion_free(client_ctx->user_ion_client,
+ client_ctx->seq_hdr_ion_handle);
+ return false;
+ }
ker_vaddr = (unsigned long) ion_map_kernel(
client_ctx->user_ion_client,
- client_ctx->seq_hdr_ion_handle, 0);
+ client_ctx->seq_hdr_ion_handle, ionflag);
if (!ker_vaddr) {
ERR("%s():get_ION_kernel virtual addr fail\n",
__func__);
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index 1dbd170..47b0f66 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -1710,6 +1710,7 @@
size_t ion_len = -1;
unsigned long phy_addr;
int rc = -1;
+ unsigned long ionflag;
if (!client_ctx || !venc_recon) {
pr_err("%s() Invalid params", __func__);
return false;
@@ -1749,10 +1750,18 @@
ERR("%s(): get_ION_handle failed\n", __func__);
goto ion_error;
}
+ rc = ion_handle_get_flags(client_ctx->user_ion_client,
+ client_ctx->recon_buffer_ion_handle[i],
+ &ionflag);
+ if (rc) {
+ ERR("%s():get_ION_flags fail\n",
+ __func__);
+ goto ion_error;
+ }
control->kernel_virtual_addr = (u8 *) ion_map_kernel(
client_ctx->user_ion_client,
client_ctx->recon_buffer_ion_handle[i],
- 0);
+ ionflag);
if (!control->kernel_virtual_addr) {
ERR("%s(): get_ION_kernel virtual addr fail\n",
__func__);
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c
index 1709cc2..f65f835 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.c
+++ b/drivers/video/msm/vidc/common/init/vidc_init.c
@@ -459,6 +459,7 @@
struct msm_mapped_buffer *mapped_buffer = NULL;
size_t ion_len;
struct ion_handle *buff_ion_handle = NULL;
+ unsigned long ionflag;
if (!client_ctx || !length)
return false;
@@ -507,11 +508,18 @@
__func__);
goto ion_error;
}
+ if (ion_handle_get_flags(client_ctx->user_ion_client,
+ buff_ion_handle,
+ &ionflag)) {
+ ERR("%s():ION flags fail\n",
+ __func__);
+ goto ion_error;
+ }
*kernel_vaddr = (unsigned long)
ion_map_kernel(
client_ctx->user_ion_client,
buff_ion_handle,
- 0);
+ ionflag);
if (!(*kernel_vaddr)) {
ERR("%s():ION virtual addr fail\n",
__func__);
diff --git a/include/linux/i2c/tsc2007.h b/include/linux/i2c/tsc2007.h
index 195e904..f439ebd 100644
--- a/include/linux/i2c/tsc2007.h
+++ b/include/linux/i2c/tsc2007.h
@@ -13,6 +13,10 @@
int fuzzx; /* fuzz factor for X, Y and pressure axes */
int fuzzy;
int fuzzz;
+ u16 min_x;
+ u16 min_y;
+ u16 max_x;
+ u16 max_y;
unsigned long irq_flags;
bool invert_x;
bool invert_y;
diff --git a/include/linux/mfd/pm8xxx/core.h b/include/linux/mfd/pm8xxx/core.h
index 5ed615b..e7bf820 100644
--- a/include/linux/mfd/pm8xxx/core.h
+++ b/include/linux/mfd/pm8xxx/core.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-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
@@ -28,6 +28,7 @@
PM8XXX_VERSION_8018,
PM8XXX_VERSION_8922,
PM8XXX_VERSION_8038,
+ PM8XXX_VERSION_8917,
};
/* PMIC version specific silicon revisions */
@@ -68,6 +69,9 @@
#define PM8XXX_REVISION_8038_2p0 2
#define PM8XXX_REVISION_8038_2p1 3
+#define PM8XXX_REVISION_8917_TEST 0
+#define PM8XXX_REVISION_8917_1p0 1
+
struct pm8xxx_drvdata {
int (*pmic_readb) (const struct device *dev,
u16 addr, u8 *val);
diff --git a/include/linux/mfd/pm8xxx/pm8921.h b/include/linux/mfd/pm8xxx/pm8921.h
index 35792d5..ee1216d 100644
--- a/include/linux/mfd/pm8xxx/pm8921.h
+++ b/include/linux/mfd/pm8xxx/pm8921.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-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
@@ -40,8 +40,10 @@
#define PM8921_NR_IRQS 256
#define PM8921_NR_GPIOS 44
+#define PM8917_NR_GPIOS 38
#define PM8921_NR_MPPS 12
+#define PM8917_NR_MPPS 10
#define PM8921_GPIO_BLOCK_START 24
#define PM8921_MPP_BLOCK_START 16
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index a984943..d905b22 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -401,6 +401,7 @@
#define CMD_CONFIG_FREE_BUF_ADDR 48
#define CMD_AXI_CFG_ZSL_ALL_CHNLS 49
#define CMD_AXI_CFG_VIDEO_ALL_CHNLS 50
+#define CMD_VFE_BUFFER_RELEASE 51
/* vfe config command: config command(from config thread)*/
struct msm_vfe_cfg_cmd {
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index 4694b78..dae4a12 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -41,6 +41,7 @@
#define MSG_ID_BUS_OVERFLOW 36
#define MSG_ID_SOF_ACK 37
#define MSG_ID_STOP_REC_ACK 38
+#define MSG_ID_STATS_AWB_AEC 39
/* ISP command IDs */
#define VFE_CMD_DUMMY_0 0
@@ -172,6 +173,13 @@
#define VFE_CMD_GET_RGB_G_TABLE 126
#define VFE_CMD_GET_LA_TABLE 127
#define VFE_CMD_DEMOSAICV3_UPDATE 128
+#define VFE_CMD_ACTIVE_REGION_CFG 129
+#define VFE_CMD_COLOR_PROCESSING_CONFIG 130
+#define VFE_CMD_STATS_WB_AEC_CONFIG 131
+#define VFE_CMD_STATS_WB_AEC_UPDATE 132
+#define VFE_CMD_Y_GAMMA_CONFIG 133
+#define VFE_CMD_SCALE_OUTPUT1_CONFIG 134
+#define VFE_CMD_SCALE_OUTPUT2_CONFIG 135
struct msm_isp_cmd {
int32_t id;
@@ -179,7 +187,6 @@
void *value;
};
-
#define VPE_CMD_DUMMY_0 0
#define VPE_CMD_INIT 1
#define VPE_CMD_DEINIT 2
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index d8d9c64..177e1d8 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -615,7 +615,7 @@
if (afe_validate_port(port_id) < 0)
return -EINVAL;
- pr_info("%s port_id=%d index %d\n", __func__, port_id, index);
+ pr_debug("%s port_id=%d index %d\n", __func__, port_id, index);
if (!(atomic_read(&this_adm.copp_cnt[index]))) {
pr_err("%s: copp count for port[%d]is 0\n", __func__, port_id);
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index a214529..302ef57 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -386,7 +386,7 @@
ret = -EINVAL;
return ret;
}
- pr_info("%s: %d %d\n", __func__, port_id, rate);
+ pr_debug("%s: %d %d\n", __func__, port_id, rate);
if ((port_id == RT_PROXY_DAI_001_RX) ||
(port_id == RT_PROXY_DAI_002_TX))
@@ -1428,7 +1428,7 @@
ret = -EINVAL;
goto fail_cmd;
}
- pr_info("%s: port_id=%d\n", __func__, port_id);
+ pr_debug("%s: port_id=%d\n", __func__, port_id);
port_id = afe_convert_virtual_to_portid(port_id);
stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -1466,7 +1466,7 @@
ret = -EINVAL;
goto fail_cmd;
}
- pr_info("%s: port_id=%d\n", __func__, port_id);
+ pr_debug("%s: port_id=%d\n", __func__, port_id);
port_id = afe_convert_virtual_to_portid(port_id);
stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,