Merge "msm: footswitch-8x60: Correct 8064 bus port IDs for video encoder/decoder" into msm-3.0
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index de314ea..88ad1a9 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -651,6 +651,26 @@
}
}
+static int cpu_has_active_perf(void)
+{
+ int idx;
+ struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+
+ if (!armpmu)
+ return 0;
+
+ for (idx = 0; idx <= armpmu->num_events; ++idx) {
+ struct perf_event *event = cpuc->events[idx];
+
+ if (event)
+ /*Even one event's existence is good enough.*/
+ return 1;
+
+ }
+
+ return 0;
+}
+
static struct pmu pmu = {
.pmu_enable = armpmu_enable,
.pmu_disable = armpmu_disable,
@@ -676,16 +696,18 @@
{
switch (cmd) {
case CPU_PM_ENTER:
- armpmu_update_counters();
- perf_pmu_disable(&pmu);
+ if (cpu_has_active_perf()) {
+ armpmu_update_counters();
+ perf_pmu_disable(&pmu);
+ }
break;
case CPU_PM_ENTER_FAILED:
case CPU_PM_EXIT:
- if (armpmu && armpmu->reset)
+ if (cpu_has_active_perf() && armpmu->reset) {
armpmu->reset(NULL);
- perf_pmu_enable(&pmu);
-
+ perf_pmu_enable(&pmu);
+ }
break;
}
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 0d25c89..99a3ed2 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -1970,6 +1970,7 @@
&apq8064_etm_device,
&apq_cpudai_slim_4_rx,
&apq_cpudai_slim_4_tx,
+ &msm8960_gemini_device,
};
static struct platform_device *sim_devices[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8930-gpu.c b/arch/arm/mach-msm/board-8930-gpu.c
index 7c8c64f..5ee480a 100644
--- a/arch/arm/mach-msm/board-8930-gpu.c
+++ b/arch/arm/mach-msm/board-8930-gpu.c
@@ -115,7 +115,7 @@
static struct kgsl_device_platform_data kgsl_3d0_pdata = {
.pwrlevel = {
{
- .gpu_freq = 450000000,
+ .gpu_freq = 400000000,
.bus_freq = 3,
.io_fraction = 0,
},
diff --git a/arch/arm/mach-msm/board-8960-gpiomux.c b/arch/arm/mach-msm/board-8960-gpiomux.c
index 9bf80ed..8b5c693 100644
--- a/arch/arm/mach-msm/board-8960-gpiomux.c
+++ b/arch/arm/mach-msm/board-8960-gpiomux.c
@@ -256,6 +256,7 @@
.pull = GPIOMUX_PULL_DOWN,
};
+#if defined(CONFIG_FB_MSM_HDMI_MHL_8334) || defined(CONFIG_FB_MSM_HDMI_MHL_9244)
static struct gpiomux_setting hdmi_active_3_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
@@ -270,6 +271,7 @@
.dir = GPIOMUX_OUT_HIGH,
};
#endif
+#endif
#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
static struct msm_gpiomux_config msm8960_ethernet_configs[] = {
@@ -690,6 +692,7 @@
[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
},
},
+#ifdef CONFIG_FB_MSM_HDMI_MHL_9244
{
.gpio = 15,
.settings = {
@@ -704,6 +707,23 @@
[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
},
},
+#endif
+#ifdef CONFIG_FB_MSM_HDMI_MHL_8334
+ {
+ .gpio = 4,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hdmi_active_3_cfg,
+ [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 15,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hdmi_active_4_cfg,
+ [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+ },
+ },
+#endif /* CONFIG_FB_MSM_HDMI_MHL */
};
#endif
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 6ed174c..c294919 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -110,6 +110,9 @@
#define KS8851_IRQ_GPIO 90
#define HAP_SHIFT_LVL_OE_GPIO 47
+#define MHL_GPIO_INT 4
+#define MHL_GPIO_RESET 15
+
#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
struct sx150x_platform_data msm8960_sx150x_data[] = {
@@ -2273,11 +2276,76 @@
},
};
+#ifdef CONFIG_FB_MSM_HDMI_MHL_8334
+static void mhl_sii_reset_gpio(int on)
+{
+ gpio_set_value(MHL_GPIO_RESET, on);
+ return;
+}
+
+/*
+ * Request for GPIO allocations
+ * Set appropriate GPIO directions
+ */
+static int mhl_sii_gpio_setup(int on)
+{
+ int ret;
+
+ if (on) {
+ ret = gpio_request(MHL_GPIO_RESET, "W_RST#");
+ if (ret < 0) {
+ pr_err("GPIO RESET request failed: %d\n", ret);
+ return -EBUSY;
+ }
+ ret = gpio_direction_output(MHL_GPIO_RESET, 1);
+ if (ret < 0) {
+ pr_err("SET GPIO RESET direction failed: %d\n", ret);
+ gpio_free(MHL_GPIO_RESET);
+ return -EBUSY;
+ }
+ ret = gpio_request(MHL_GPIO_INT, "W_INT");
+ if (ret < 0) {
+ pr_err("GPIO INT request failed: %d\n", ret);
+ gpio_free(MHL_GPIO_RESET);
+ return -EBUSY;
+ }
+ ret = gpio_direction_input(MHL_GPIO_INT);
+ if (ret < 0) {
+ pr_err("SET GPIO INTR direction failed: %d\n", ret);
+ gpio_free(MHL_GPIO_RESET);
+ gpio_free(MHL_GPIO_INT);
+ return -EBUSY;
+ }
+ } else {
+ gpio_free(MHL_GPIO_RESET);
+ gpio_free(MHL_GPIO_INT);
+ }
+
+ return 0;
+}
+
+static struct msm_mhl_platform_data mhl_platform_data = {
+ .irq = MSM_GPIO_TO_INT(4),
+ .gpio_setup = mhl_sii_gpio_setup,
+ .reset_pin = mhl_sii_reset_gpio,
+};
+#endif
+
static struct i2c_board_info sii_device_info[] __initdata = {
{
+#ifdef CONFIG_FB_MSM_HDMI_MHL_8334
+ /*
+ * keeps SI 8334 as the default
+ * MHL TX
+ */
+ I2C_BOARD_INFO("sii8334", 0x39),
+ .platform_data = &mhl_platform_data,
+#endif
+#ifdef CONFIG_FB_MSM_HDMI_MHL_9244
I2C_BOARD_INFO("Sil-9244", 0x39),
- .flags = I2C_CLIENT_WAKE,
.irq = MSM_GPIO_TO_INT(15),
+#endif /* CONFIG_MSM_HDMI_MHL */
+ .flags = I2C_CLIENT_WAKE,
},
};
@@ -2902,7 +2970,7 @@
ARRAY_SIZE(mxt_device_info),
},
{
- I2C_FFA | I2C_LIQUID,
+ I2C_SURF | I2C_FFA | I2C_LIQUID,
MSM_8960_GSBI10_QUP_I2C_BUS_ID,
sii_device_info,
ARRAY_SIZE(sii_device_info),
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index 28f5e7f..55c5fd9 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -380,6 +380,7 @@
}
static struct clk_lookup msm_clocks_dummy[] = {
+ CLK_DUMMY("xo", XO_CLK, NULL, OFF),
CLK_DUMMY("core_clk", BLSP2_UART_CLK, "msm_serial_hsl.0", OFF),
CLK_DUMMY("iface_clk", BLSP2_UART_CLK, "msm_serial_hsl.0", OFF),
CLK_DUMMY("core_clk", SDC1_CLK, NULL, OFF),
diff --git a/arch/arm/mach-msm/cache_erp.c b/arch/arm/mach-msm/cache_erp.c
index 1eb229a..9a721e4 100644
--- a/arch/arm/mach-msm/cache_erp.c
+++ b/arch/arm/mach-msm/cache_erp.c
@@ -28,6 +28,9 @@
#define CESR_TLBMH BIT(16)
#define CESR_I_MASK 0x000000CC
+/* Print a message for everything but TLB MH events */
+#define CESR_PRINT_MASK 0x000000FF
+
#define L2ESR_IND_ADDR 0x204
#define L2ESYNR0_IND_ADDR 0x208
#define L2ESYNR1_IND_ADDR 0x209
@@ -190,9 +193,12 @@
struct msm_l1_err_stats *l1_stats = dev_id;
unsigned int cesr = read_cesr();
unsigned int i_cesynr, d_cesynr;
+ int print_regs = cesr & CESR_PRINT_MASK;
- pr_alert("L1 Error detected on CPU %d!\n", smp_processor_id());
- pr_alert("\tCESR = 0x%08x\n", cesr);
+ if (print_regs) {
+ pr_alert("L1 Error detected on CPU %d!\n", smp_processor_id());
+ pr_alert("\tCESR = 0x%08x\n", cesr);
+ }
if (cesr & CESR_DCTPE) {
pr_alert("D-cache tag parity error\n");
@@ -225,7 +231,7 @@
}
if (cesr & CESR_TLBMH) {
- pr_alert("TLB multi-hit error\n");
+ asm ("mcr p15, 0, r0, c8, c7, 0");
l1_stats->tlbmh++;
}
@@ -250,7 +256,8 @@
/* Clear the interrupt bits we processed */
write_cesr(cesr);
- ERP_L1_ERR("L1 cache / TLB error detected");
+ if (print_regs)
+ ERP_L1_ERR("L1 cache error detected");
return IRQ_HANDLED;
}
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
index 5951734..d124ba6 100644
--- a/arch/arm/mach-msm/clock-7x30.c
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -2800,8 +2800,8 @@
OWN(APPS1, 6, "iface_clk", grp_2d_p_clk, "kgsl-2d0.0"),
OWN(APPS1, 6, "iface_clk", grp_2d_p_clk, "footswitch-pcom.0"),
OWN(APPS1, 31, "hdmi_clk", hdmi_clk, "dtv.0"),
- OWN(APPS1, 0, "jpeg_clk", jpeg_clk, NULL),
- OWN(APPS1, 0, "jpeg_pclk", jpeg_p_clk, NULL),
+ OWN(APPS1, 0, "jpeg_clk", jpeg_clk, "msm_gemini.0"),
+ OWN(APPS1, 0, "jpeg_pclk", jpeg_p_clk, "msm_gemini.0"),
OWN(APPS1, 23, "lpa_codec_clk", lpa_codec_clk, NULL),
OWN(APPS1, 23, "lpa_core_clk", lpa_core_clk, NULL),
OWN(APPS1, 23, "lpa_pclk", lpa_p_clk, NULL),
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 0ebaaab..3f7206f 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5047,8 +5047,8 @@
CLK_LOOKUP("vcap_npl_clk", vcap_npl_clk.c, ""),
CLK_LOOKUP("vcap_npl_clk", vcap_npl_clk.c, "msm_vcap.0"),
CLK_LOOKUP("bus_clk", ijpeg_axi_clk.c, "footswitch-8x60.3"),
- CLK_LOOKUP("mem_clk", imem_axi_clk.c, ""),
- CLK_LOOKUP("ijpeg_clk", ijpeg_clk.c, ""),
+ CLK_LOOKUP("imem_clk", imem_axi_clk.c, "msm_gemini.0"),
+ CLK_LOOKUP("ijpeg_clk", ijpeg_clk.c, "msm_gemini.0"),
CLK_LOOKUP("core_clk", ijpeg_clk.c, "footswitch-8x60.3"),
CLK_LOOKUP("core_clk", jpegd_clk.c, ""),
CLK_LOOKUP("core_clk", mdp_clk.c, "mdp.0"),
@@ -5093,7 +5093,7 @@
CLK_LOOKUP("iface_clk", gfx3d_p_clk.c, "footswitch-8x60.2"),
CLK_LOOKUP("master_iface_clk", hdmi_m_p_clk.c, "hdmi_msm.1"),
CLK_LOOKUP("slave_iface_clk", hdmi_s_p_clk.c, "hdmi_msm.1"),
- CLK_LOOKUP("ijpeg_pclk", ijpeg_p_clk.c, ""),
+ CLK_LOOKUP("ijpeg_pclk", ijpeg_p_clk.c, "msm_gemini.0"),
CLK_LOOKUP("iface_clk", ijpeg_p_clk.c, "footswitch-8x60.3"),
CLK_LOOKUP("iface_clk", jpegd_p_clk.c, ""),
CLK_LOOKUP("mem_iface_clk", imem_p_clk.c, "kgsl-3d0.0"),
@@ -5349,8 +5349,8 @@
CLK_LOOKUP("core_clk", gfx3d_clk.c, "kgsl-3d0.0"),
CLK_LOOKUP("core_clk", gfx3d_clk.c, "footswitch-8x60.2"),
CLK_LOOKUP("bus_clk", ijpeg_axi_clk.c, "footswitch-8x60.3"),
- CLK_LOOKUP("imem_clk", imem_axi_clk.c, NULL),
- CLK_LOOKUP("ijpeg_clk", ijpeg_clk.c, NULL),
+ CLK_LOOKUP("imem_clk", imem_axi_clk.c, "msm_gemini.0"),
+ CLK_LOOKUP("ijpeg_clk", ijpeg_clk.c, "msm_gemini.0"),
CLK_LOOKUP("core_clk", ijpeg_clk.c, "footswitch-8x60.3"),
CLK_LOOKUP("core_clk", jpegd_clk.c, ""),
CLK_LOOKUP("core_clk", mdp_clk.c, "mdp.0"),
@@ -5402,7 +5402,7 @@
CLK_LOOKUP("iface_clk", gfx3d_p_clk.c, "footswitch-8x60.2"),
CLK_LOOKUP("master_iface_clk", hdmi_m_p_clk.c, "hdmi_msm.1"),
CLK_LOOKUP("slave_iface_clk", hdmi_s_p_clk.c, "hdmi_msm.1"),
- CLK_LOOKUP("ijpeg_pclk", ijpeg_p_clk.c, NULL),
+ CLK_LOOKUP("ijpeg_pclk", ijpeg_p_clk.c, "msm_gemini.0"),
CLK_LOOKUP("iface_clk", ijpeg_p_clk.c, "footswitch-8x60.3"),
CLK_LOOKUP("iface_clk", jpegd_p_clk.c, ""),
CLK_LOOKUP("mem_iface_clk", imem_p_clk.c, "kgsl-3d0.0"),
@@ -5638,8 +5638,8 @@
CLK_LOOKUP("bus_clk",
gfx3d_axi_clk_8930.c, "footswitch-8x60.2"),
CLK_LOOKUP("bus_clk", ijpeg_axi_clk.c, "footswitch-8x60.3"),
- CLK_LOOKUP("imem_clk", imem_axi_clk.c, NULL),
- CLK_LOOKUP("ijpeg_clk", ijpeg_clk.c, NULL),
+ CLK_LOOKUP("imem_clk", imem_axi_clk.c, "msm_gemini.0"),
+ CLK_LOOKUP("ijpeg_clk", ijpeg_clk.c, "msm_gemini.0"),
CLK_LOOKUP("core_clk", ijpeg_clk.c, "footswitch-8x60.3"),
CLK_LOOKUP("core_clk", mdp_clk.c, "mdp.0"),
CLK_LOOKUP("core_clk", mdp_clk.c, "footswitch-8x60.4"),
@@ -5682,7 +5682,7 @@
CLK_LOOKUP("iface_clk", gfx3d_p_clk.c, "footswitch-8x60.2"),
CLK_LOOKUP("master_iface_clk", hdmi_m_p_clk.c, "hdmi_msm.1"),
CLK_LOOKUP("slave_iface_clk", hdmi_s_p_clk.c, "hdmi_msm.1"),
- CLK_LOOKUP("ijpeg_pclk", ijpeg_p_clk.c, NULL),
+ CLK_LOOKUP("ijpeg_pclk", ijpeg_p_clk.c, "msm_gemini.0"),
CLK_LOOKUP("iface_clk", ijpeg_p_clk.c, "footswitch-8x60.3"),
CLK_LOOKUP("mem_iface_clk", imem_p_clk.c, "kgsl-3d0.0"),
CLK_LOOKUP("iface_clk", mdp_p_clk.c, "mdp.0"),
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index a1bbf53..2bfadf6 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -3613,7 +3613,7 @@
CLK_LOOKUP("core_clk", gfx2d1_clk.c, "footswitch-8x60.1"),
CLK_LOOKUP("core_clk", gfx3d_clk.c, "kgsl-3d0.0"),
CLK_LOOKUP("core_clk", gfx3d_clk.c, "footswitch-8x60.2"),
- CLK_LOOKUP("ijpeg_clk", ijpeg_clk.c, NULL),
+ CLK_LOOKUP("ijpeg_clk", ijpeg_clk.c, "msm_gemini.0"),
CLK_LOOKUP("core_clk", ijpeg_clk.c, "footswitch-8x60.3"),
CLK_LOOKUP("core_clk", jpegd_clk.c, NULL),
CLK_LOOKUP("core_clk", mdp_clk.c, "mdp.0"),
@@ -3666,7 +3666,7 @@
CLK_LOOKUP("iface_clk", gfx3d_p_clk.c, "footswitch-8x60.2"),
CLK_LOOKUP("master_iface_clk", hdmi_m_p_clk.c, "hdmi_msm.1"),
CLK_LOOKUP("slave_iface_clk", hdmi_s_p_clk.c, "hdmi_msm.1"),
- CLK_LOOKUP("ijpeg_pclk", ijpeg_p_clk.c, NULL),
+ CLK_LOOKUP("ijpeg_pclk", ijpeg_p_clk.c, "msm_gemini.0"),
CLK_LOOKUP("iface_clk", ijpeg_p_clk.c, "footswitch-8x60.3"),
CLK_LOOKUP("iface_clk", jpegd_p_clk.c, NULL),
CLK_LOOKUP("mem_iface_clk", imem_p_clk.c, "kgsl-3d0.0"),
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index e83f17a..5022811 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -45,9 +45,11 @@
static DEFINE_SPINLOCK(pll_reg_lock);
+#define ENABLE_WAIT_MAX_LOOPS 200
+
int pll_vote_clk_enable(struct clk *clk)
{
- u32 ena;
+ u32 ena, count;
unsigned long flags;
struct pll_vote_clk *pll = to_pll_vote_clk(clk);
@@ -57,11 +59,22 @@
writel_relaxed(ena, PLL_EN_REG(pll));
spin_unlock_irqrestore(&pll_reg_lock, flags);
- /* Wait until PLL is enabled */
- while ((readl_relaxed(PLL_STATUS_REG(pll)) & pll->status_mask) == 0)
- cpu_relax();
+ /*
+ * Use a memory barrier since some PLL status registers are
+ * not within the same 1K segment as the voting registers.
+ */
+ mb();
- return 0;
+ /* Wait for pll to enable. */
+ for (count = ENABLE_WAIT_MAX_LOOPS; count > 0; count--) {
+ if (readl_relaxed(pll->status_reg) & pll->status_mask)
+ return 0;
+ udelay(1);
+ }
+
+ WARN("PLL %s didn't enable after voting for it!\n", clk->dbg_name);
+
+ return -ETIMEDOUT;
}
void pll_vote_clk_disable(struct clk *clk)
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
index 4ba3f95..b68fdc1 100644
--- a/arch/arm/mach-msm/cpuidle.c
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -30,28 +30,40 @@
{0, 0, "C0", "WFI",
MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
- {0, 1, "C1", "STANDALONE_POWER_COLLAPSE",
+ {0, 1, "C1", "RETENTION",
+ MSM_PM_SLEEP_MODE_RETENTION},
+
+ {0, 2, "C2", "STANDALONE_POWER_COLLAPSE",
MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
- {0, 2, "C2", "POWER_COLLAPSE",
+ {0, 3, "C3", "POWER_COLLAPSE",
MSM_PM_SLEEP_MODE_POWER_COLLAPSE},
{1, 0, "C0", "WFI",
MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
- {1, 1, "C1", "STANDALONE_POWER_COLLAPSE",
+ {1, 1, "C1", "RETENTION",
+ MSM_PM_SLEEP_MODE_RETENTION},
+
+ {1, 2, "C2", "STANDALONE_POWER_COLLAPSE",
MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
{2, 0, "C0", "WFI",
MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
- {2, 1, "C1", "STANDALONE_POWER_COLLAPSE",
+ {2, 1, "C1", "RETENTION",
+ MSM_PM_SLEEP_MODE_RETENTION},
+
+ {2, 2, "C2", "STANDALONE_POWER_COLLAPSE",
MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
{3, 0, "C0", "WFI",
MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
- {3, 1, "C1", "STANDALONE_POWER_COLLAPSE",
+ {3, 1, "C1", "RETENTION",
+ MSM_PM_SLEEP_MODE_RETENTION},
+
+ {3, 2, "C2", "STANDALONE_POWER_COLLAPSE",
MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
};
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 36cdd86..c46c493 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -475,6 +475,12 @@
bool (*check_hdcp_hw_support)(void);
};
+struct msm_mhl_platform_data {
+ int irq;
+ int (*gpio_setup)(int on);
+ void (*reset_pin)(int on);
+};
+
struct msm_i2c_platform_data {
int clk_freq;
uint32_t rmutex;
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index e6a0175..04cfa71 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -638,8 +638,6 @@
};
int msm_camio_enable(struct platform_device *dev);
-int msm_camio_jpeg_clk_enable(void);
-int msm_camio_jpeg_clk_disable(void);
int msm_camio_vpe_clk_enable(uint32_t);
int msm_camio_vpe_clk_disable(void);
diff --git a/arch/arm/mach-msm/include/mach/iommu_domains.h b/arch/arm/mach-msm/include/mach/iommu_domains.h
index c17795a..74e1115 100644
--- a/arch/arm/mach-msm/include/mach/iommu_domains.h
+++ b/arch/arm/mach-msm/include/mach/iommu_domains.h
@@ -42,10 +42,6 @@
unsigned int partition_no,
unsigned long size);
-extern unsigned long msm_subsystem_get_domain_no(int subsys_id);
-
-extern unsigned long msm_subsystem_get_partition_no(int subsys_id);
-
extern int msm_use_iommu(void);
extern int msm_iommu_map_extra(struct iommu_domain *domain,
@@ -69,16 +65,6 @@
unsigned int partition_no,
unsigned long size) { return; }
-static inline unsigned long msm_subsystem_get_domain_no(int subsys_id)
-{
- return 0xFFFFFFFF;
-}
-
-static inline unsigned long msm_subsystem_get_partition_no(int subsys_id)
-{
- return 0xFFFFFFFF;
-}
-
static inline int msm_use_iommu(void)
{
return 0;
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index 1959f5d..dbc1389 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -227,40 +227,6 @@
return NULL;
}
-static unsigned long subsystem_to_domain_tbl[] = {
- VIDEO_DOMAIN,
- VIDEO_DOMAIN,
- CAMERA_DOMAIN,
- DISPLAY_DOMAIN,
- ROTATOR_DOMAIN,
- 0xFFFFFFFF
-};
-
-unsigned long msm_subsystem_get_domain_no(int subsys_id)
-{
- if (subsys_id > INVALID_SUBSYS_ID && subsys_id <= MAX_SUBSYSTEM_ID &&
- subsys_id < ARRAY_SIZE(subsystem_to_domain_tbl))
- return subsystem_to_domain_tbl[subsys_id];
- else
- return subsystem_to_domain_tbl[MAX_SUBSYSTEM_ID];
-}
-
-unsigned long msm_subsystem_get_partition_no(int subsys_id)
-{
- switch (subsys_id) {
- case MSM_SUBSYSTEM_VIDEO_FWARE:
- return VIDEO_FIRMWARE_POOL;
- case MSM_SUBSYSTEM_VIDEO:
- return VIDEO_MAIN_POOL;
- case MSM_SUBSYSTEM_CAMERA:
- case MSM_SUBSYSTEM_DISPLAY:
- case MSM_SUBSYSTEM_ROTATOR:
- return GEN_POOL;
- default:
- return 0xFFFFFFFF;
- }
-}
-
unsigned long msm_allocate_iova_address(unsigned int iommu_domain,
unsigned int partition_no,
unsigned long size,
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index a90be23..462543e 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -138,7 +138,7 @@
struct msm_ipc_sock {
struct sock sk;
struct msm_ipc_port *port;
- void *default_pil;
+ void *modem_pil;
};
enum write_data_type {
@@ -206,15 +206,4 @@
int msm_ipc_router_init_sockets(void);
void msm_ipc_router_exit_sockets(void);
-#if defined CONFIG_MSM_IPC_ROUTER_SMD_XPRT
-extern void *msm_ipc_load_default_node(void);
-
-extern void msm_ipc_unload_default_node(void *pil);
-#else
-static inline void *msm_ipc_load_default_node(void)
-{ return NULL; }
-
-static inline void msm_ipc_unload_default_node(void *pil) { }
-#endif
-
#endif
diff --git a/arch/arm/mach-msm/ipc_router_smd_xprt.c b/arch/arm/mach-msm/ipc_router_smd_xprt.c
index 307b6ae..0cde393 100644
--- a/arch/arm/mach-msm/ipc_router_smd_xprt.c
+++ b/arch/arm/mach-msm/ipc_router_smd_xprt.c
@@ -19,7 +19,6 @@
#include <linux/types.h>
#include <mach/msm_smd.h>
-#include <mach/peripheral-loader.h>
#include "ipc_router.h"
#include "smd_private.h"
@@ -443,31 +442,6 @@
return 0;
}
-void *msm_ipc_load_default_node(void)
-{
- void *pil = NULL;
- const char *peripheral;
-
- peripheral = smd_edge_to_subsystem(SMD_APPS_MODEM);
- if (peripheral && !strncmp(peripheral, "modem", 6)) {
- pil = pil_get(peripheral);
- if (IS_ERR(pil)) {
- pr_err("%s: Failed to load %s\n",
- __func__, peripheral);
- pil = NULL;
- }
- }
- return pil;
-}
-EXPORT_SYMBOL(msm_ipc_load_default_node);
-
-void msm_ipc_unload_default_node(void *pil)
-{
- if (pil)
- pil_put(pil);
-}
-EXPORT_SYMBOL(msm_ipc_unload_default_node);
-
static struct platform_driver msm_ipc_router_smd_remote_driver[] = {
{
.probe = msm_ipc_router_smd_remote_probe,
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index d1ed538..6e8c99e 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -26,15 +26,58 @@
#include <net/sock.h>
+#include <mach/peripheral-loader.h>
+#include <mach/socinfo.h>
+
#include "ipc_router.h"
#define msm_ipc_sk(sk) ((struct msm_ipc_sock *)(sk))
#define msm_ipc_sk_port(sk) ((struct msm_ipc_port *)(msm_ipc_sk(sk)->port))
+#define MODEM_LOAD_TIMEOUT (10 * HZ)
static int sockets_enabled;
static struct proto msm_ipc_proto;
static const struct proto_ops msm_ipc_proto_ops;
+static void msm_ipc_router_unload_modem(void *pil)
+{
+ if (pil)
+ pil_put(pil);
+}
+
+static void *msm_ipc_router_load_modem(void)
+{
+ void *pil = NULL;
+ int rc;
+
+ /* Load GNSS for Standalone 8064 but not for Fusion 3 */
+ if (cpu_is_apq8064()) {
+ if (socinfo_get_platform_subtype() == 0x0)
+ pil = pil_get("gss");
+ } else {
+ pil = pil_get("modem");
+ }
+
+ if (IS_ERR(pil) || !pil) {
+ pr_debug("%s: modem load failed\n", __func__);
+ pil = NULL;
+ } else {
+ rc = wait_for_completion_interruptible_timeout(
+ &msm_ipc_remote_router_up,
+ MODEM_LOAD_TIMEOUT);
+ if (!rc)
+ rc = -ETIMEDOUT;
+ if (rc < 0) {
+ pr_err("%s: wait for remote router failed %d\n",
+ __func__, rc);
+ msm_ipc_router_unload_modem(pil);
+ pil = NULL;
+ }
+ }
+
+ return pil;
+}
+
static struct sk_buff_head *msm_ipc_router_build_msg(unsigned int num_sect,
struct iovec const *msg_sect,
size_t total_len)
@@ -201,9 +244,9 @@
sock_init_data(sock, sk);
sk->sk_rcvtimeo = DEFAULT_RCV_TIMEO;
- pil = msm_ipc_load_default_node();
+ pil = msm_ipc_router_load_modem();
msm_ipc_sk(sk)->port = port_ptr;
- msm_ipc_sk(sk)->default_pil = pil;
+ msm_ipc_sk(sk)->modem_pil = pil;
return 0;
}
@@ -452,12 +495,12 @@
{
struct sock *sk = sock->sk;
struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
- void *pil = msm_ipc_sk(sk)->default_pil;
+ void *pil = msm_ipc_sk(sk)->modem_pil;
int ret;
lock_sock(sk);
ret = msm_ipc_router_close_port(port_ptr);
- msm_ipc_unload_default_node(pil);
+ msm_ipc_router_unload_modem(pil);
release_sock(sk);
sock_put(sk);
sock->sk = NULL;
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
new file mode 100644
index 0000000..cd58a4c
--- /dev/null
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -0,0 +1,199 @@
+/*
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/elf.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+
+#include "peripheral-loader.h"
+#include "pil-q6v5.h"
+
+/* Register Offsets */
+#define QDSP6SS_RESET 0x014
+#define QDSP6SS_GFMUX_CTL 0x020
+#define QDSP6SS_PWR_CTL 0x030
+
+/* QDSP6SS_RESET */
+#define Q6SS_CORE_ARES BIT(1)
+#define Q6SS_ETM_ISDB_ARES BIT(3)
+#define Q6SS_STOP_CORE BIT(4)
+
+/* QDSP6SS_GFMUX_CTL */
+#define Q6SS_CLK_ENA BIT(1)
+
+/* QDSP6SS_PWR_CTL */
+#define Q6SS_L2DATA_SLP_NRET_N BIT(0)
+#define Q6SS_L2TAG_SLP_NRET_N BIT(16)
+#define Q6SS_ETB_SLP_NRET_N BIT(17)
+#define Q6SS_L2DATA_STBY_N BIT(18)
+#define Q6SS_SLP_RET_N BIT(19)
+#define Q6SS_CLAMP_IO BIT(20)
+#define QDSS_BHS_ON BIT(21)
+
+int pil_q6v5_make_proxy_votes(struct pil_desc *pil)
+{
+ int ret;
+ struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+
+ ret = clk_prepare_enable(drv->xo);
+ if (ret) {
+ dev_err(pil->dev, "Failed to enable XO\n");
+ return ret;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(pil_q6v5_make_proxy_votes);
+
+void pil_q6v5_remove_proxy_votes(struct pil_desc *pil)
+{
+ struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ clk_disable_unprepare(drv->xo);
+}
+EXPORT_SYMBOL(pil_q6v5_remove_proxy_votes);
+
+int pil_q6v5_init_image(struct pil_desc *pil, const u8 *metadata,
+ size_t size)
+{
+ const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
+ struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ drv->start_addr = ehdr->e_entry;
+ return 0;
+}
+EXPORT_SYMBOL(pil_q6v5_init_image);
+
+void pil_q6v5_shutdown(struct pil_desc *pil)
+{
+ u32 val;
+ struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+
+ /* Turn off core clock */
+ val = readl_relaxed(drv->reg_base + QDSP6SS_GFMUX_CTL);
+ val &= ~Q6SS_CLK_ENA;
+ writel_relaxed(val, drv->reg_base + QDSP6SS_GFMUX_CTL);
+
+ /* Clamp IO */
+ val = readl_relaxed(drv->reg_base + QDSP6SS_PWR_CTL);
+ val |= Q6SS_CLAMP_IO;
+ writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
+
+ /* Turn off Q6 memories */
+ val &= ~(Q6SS_L2DATA_SLP_NRET_N | Q6SS_SLP_RET_N |
+ Q6SS_L2TAG_SLP_NRET_N | Q6SS_ETB_SLP_NRET_N |
+ Q6SS_L2DATA_STBY_N);
+ writel_relaxed(Q6SS_CLAMP_IO, drv->reg_base + QDSP6SS_PWR_CTL);
+
+ /* Assert Q6 resets */
+ val = readl_relaxed(drv->reg_base + QDSP6SS_RESET);
+ val = (Q6SS_CORE_ARES | Q6SS_ETM_ISDB_ARES);
+ writel_relaxed(val, drv->reg_base + QDSP6SS_RESET);
+
+ /* Kill power at block headswitch (affects LPASS only) */
+ val = readl_relaxed(drv->reg_base + QDSP6SS_PWR_CTL);
+ val &= ~QDSS_BHS_ON;
+ writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
+}
+EXPORT_SYMBOL(pil_q6v5_shutdown);
+
+int pil_q6v5_reset(struct pil_desc *pil)
+{
+ struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ u32 val;
+
+ /* Assert resets, stop core */
+ val = readl_relaxed(drv->reg_base + QDSP6SS_RESET);
+ val |= (Q6SS_CORE_ARES | Q6SS_ETM_ISDB_ARES | Q6SS_STOP_CORE);
+ writel_relaxed(val, drv->reg_base + QDSP6SS_RESET);
+
+ /* Enable power block headswitch (only affects LPASS) */
+ val = readl_relaxed(drv->reg_base + QDSP6SS_PWR_CTL);
+ val |= QDSS_BHS_ON;
+ writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
+
+ /* Turn on memories */
+ val = readl_relaxed(drv->reg_base + QDSP6SS_PWR_CTL);
+ val |= Q6SS_L2DATA_SLP_NRET_N | Q6SS_SLP_RET_N |
+ Q6SS_L2TAG_SLP_NRET_N | Q6SS_ETB_SLP_NRET_N |
+ Q6SS_L2DATA_STBY_N;
+ writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
+
+ /* Remove IO clamp */
+ val &= ~Q6SS_CLAMP_IO;
+ writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
+
+ /* Bring core out of reset */
+ val = Q6SS_STOP_CORE;
+ writel_relaxed(val, drv->reg_base + QDSP6SS_RESET);
+
+ /* Turn on core clock */
+ val = readl_relaxed(drv->reg_base + QDSP6SS_GFMUX_CTL);
+ val |= Q6SS_CLK_ENA;
+ writel_relaxed(val, drv->reg_base + QDSP6SS_GFMUX_CTL);
+
+ /* Start core execution */
+ val = readl_relaxed(drv->reg_base + QDSP6SS_RESET);
+ val &= ~Q6SS_STOP_CORE;
+ writel_relaxed(val, drv->reg_base + QDSP6SS_RESET);
+
+ return 0;
+}
+EXPORT_SYMBOL(pil_q6v5_reset);
+
+struct pil_desc __devinit *pil_q6v5_init(struct platform_device *pdev)
+{
+ struct q6v5_data *drv;
+ struct resource *res;
+ struct pil_desc *desc;
+ int ret;
+
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return ERR_PTR(-ENOMEM);
+ platform_set_drvdata(pdev, drv);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return ERR_PTR(-EINVAL);
+ drv->reg_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!drv->reg_base)
+ return ERR_PTR(-ENOMEM);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ drv->clk_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!drv->clk_base)
+ return ERR_PTR(-ENOMEM);
+
+ desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return ERR_PTR(-ENOMEM);
+
+ ret = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
+ &desc->name);
+ if (ret)
+ return ERR_PTR(ret);
+
+ drv->xo = devm_clk_get(&pdev->dev, "xo");
+ if (IS_ERR(drv->xo))
+ return ERR_CAST(drv->xo);
+
+ desc->dev = &pdev->dev;
+
+ return desc;
+}
+EXPORT_SYMBOL(pil_q6v5_init);
diff --git a/arch/arm/mach-msm/pil-q6v5.h b/arch/arm/mach-msm/pil-q6v5.h
new file mode 100644
index 0000000..23471d1
--- /dev/null
+++ b/arch/arm/mach-msm/pil-q6v5.h
@@ -0,0 +1,42 @@
+/*
+ * 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_PIL_Q6V5_H
+#define __MSM_PIL_Q6V5_H
+
+struct regulator;
+struct clk;
+struct pil_device;
+struct pil_desc;
+struct platform_device;
+
+struct q6v5_data {
+ void __iomem *reg_base;
+ void __iomem *clk_base;
+ void __iomem *rmb_base;
+ unsigned long start_addr;
+ struct regulator *vreg;
+ bool vreg_enabled;
+ int self_auth;
+ struct clk *xo;
+ struct pil_device *pil;
+};
+
+int pil_q6v5_make_proxy_votes(struct pil_desc *pil);
+void pil_q6v5_remove_proxy_votes(struct pil_desc *pil);
+int pil_q6v5_init_image(struct pil_desc *pil, const u8 *metadata,
+ size_t size);
+void pil_q6v5_shutdown(struct pil_desc *pil);
+int pil_q6v5_reset(struct pil_desc *pil);
+struct pil_desc *pil_q6v5_init(struct platform_device *pdev);
+
+#endif
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 2b0cc18..43e7032 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -105,6 +105,7 @@
static char *msm_pm_sleep_mode_labels[MSM_PM_SLEEP_MODE_NR] = {
[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = "power_collapse",
[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = "wfi",
+ [MSM_PM_SLEEP_MODE_RETENTION] = "retention",
[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE] =
"standalone_power_collapse",
};
@@ -324,6 +325,7 @@
enum msm_pm_time_stats_id {
MSM_PM_STAT_REQUESTED_IDLE,
MSM_PM_STAT_IDLE_WFI,
+ MSM_PM_STAT_RETENTION,
MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
MSM_PM_STAT_IDLE_POWER_COLLAPSE,
MSM_PM_STAT_SUSPEND,
@@ -617,6 +619,19 @@
msm_arch_idle();
}
+
+static void msm_pm_retention(void)
+{
+ int ret = 0;
+
+ msm_pm_config_hw_before_swfi();
+ ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_RETENTION, false);
+ WARN_ON(ret);
+ msm_arch_idle();
+ ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
+ WARN_ON(ret);
+}
+
#ifdef CONFIG_CACHE_L2X0
static inline bool msm_pm_l2x0_power_collapse(void)
{
@@ -810,6 +825,11 @@
}
/* fall through */
+ case MSM_PM_SLEEP_MODE_RETENTION:
+ if (!allow)
+ break;
+ /* fall through */
+
case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
if (!allow)
break;
@@ -884,6 +904,13 @@
#endif
break;
+ case MSM_PM_SLEEP_MODE_RETENTION:
+ msm_pm_retention();
+#ifdef CONFIG_MSM_IDLE_STATS
+ exit_stat = MSM_PM_STAT_RETENTION;
+#endif
+ break;
+
case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
msm_pm_power_collapse_standalone(true);
#ifdef CONFIG_MSM_IDLE_STATS
@@ -982,6 +1009,10 @@
per_cpu(msm_pm_last_slp_mode, cpu)
= MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE;
msm_pm_power_collapse_standalone(false);
+ } else if (allow[MSM_PM_SLEEP_MODE_RETENTION]) {
+ per_cpu(msm_pm_last_slp_mode, cpu)
+ = MSM_PM_SLEEP_MODE_RETENTION;
+ msm_pm_retention();
} else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
per_cpu(msm_pm_last_slp_mode, cpu)
= MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE;
@@ -1108,6 +1139,10 @@
if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
pr_info("%s: standalone power collapse\n", __func__);
msm_pm_power_collapse_standalone(false);
+ } else if (allow[MSM_PM_SLEEP_MODE_RETENTION]) {
+ if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
+ pr_info("%s: retention\n", __func__);
+ msm_pm_retention();
} else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
pr_info("%s: swfi\n", __func__);
@@ -1195,6 +1230,10 @@
stats[MSM_PM_STAT_IDLE_WFI].first_bucket_time =
CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+ stats[MSM_PM_STAT_RETENTION].name = "retention";
+ stats[MSM_PM_STAT_RETENTION].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].name =
"idle-standalone-power-collapse";
stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].
diff --git a/arch/arm/mach-msm/pm-data.c b/arch/arm/mach-msm/pm-data.c
index d7001d7..6f4743f 100644
--- a/arch/arm/mach-msm/pm-data.c
+++ b/arch/arm/mach-msm/pm-data.c
@@ -28,6 +28,13 @@
.suspend_enabled = 0,
},
+ [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_RETENTION)] = {
+ .idle_supported = 1,
+ .suspend_supported = 1,
+ .idle_enabled = 0,
+ .suspend_enabled = 0,
+ },
+
[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
.idle_supported = 1,
.suspend_supported = 1,
@@ -49,6 +56,13 @@
.suspend_enabled = 0,
},
+ [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_RETENTION)] = {
+ .idle_supported = 1,
+ .suspend_supported = 1,
+ .idle_enabled = 0,
+ .suspend_enabled = 0,
+ },
+
[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
.idle_supported = 1,
.suspend_supported = 0,
@@ -70,6 +84,13 @@
.suspend_enabled = 0,
},
+ [MSM_PM_MODE(2, MSM_PM_SLEEP_MODE_RETENTION)] = {
+ .idle_supported = 1,
+ .suspend_supported = 1,
+ .idle_enabled = 0,
+ .suspend_enabled = 0,
+ },
+
[MSM_PM_MODE(2, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
.idle_supported = 1,
.suspend_supported = 0,
@@ -91,6 +112,13 @@
.suspend_enabled = 0,
},
+ [MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_RETENTION)] = {
+ .idle_supported = 1,
+ .suspend_supported = 1,
+ .idle_enabled = 0,
+ .suspend_enabled = 0,
+ },
+
[MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
.idle_supported = 1,
.suspend_supported = 0,
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 7ef3c34..09494a0 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -44,13 +44,14 @@
};
enum msm_pm_sleep_mode {
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND,
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
- MSM_PM_SLEEP_MODE_APPS_SLEEP,
- MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT,
- MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN,
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
+ MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT = 0,
+ MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT = 1,
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE = 2,
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE = 3,
+ MSM_PM_SLEEP_MODE_APPS_SLEEP = 4,
+ MSM_PM_SLEEP_MODE_RETENTION = MSM_PM_SLEEP_MODE_APPS_SLEEP,
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND = 5,
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN = 6,
MSM_PM_SLEEP_MODE_NR
};
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index 48e0135..ba3129d8 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -946,8 +946,15 @@
ac = audio->ac;
/* Offset with appropriate meta */
- param.paddr = buf_node->paddr + sizeof(struct dec_meta_in);
- param.len = buf_node->buf.data_len - sizeof(struct dec_meta_in);
+ if (audio->feedback) {
+ /* Non Tunnel mode */
+ param.paddr = buf_node->paddr + sizeof(struct dec_meta_in);
+ param.len = buf_node->buf.data_len - sizeof(struct dec_meta_in);
+ } else {
+ /* Tunnel mode */
+ param.paddr = buf_node->paddr;
+ param.len = buf_node->buf.data_len;
+ }
param.msw_ts = buf_node->meta_info.meta_in.ntimestamp.highpart;
param.lsw_ts = buf_node->meta_info.meta_in.ntimestamp.lowpart;
/* If no meta_info enaled, indicate no time stamp valid */
diff --git a/arch/arm/mach-msm/subsystem_map.c b/arch/arm/mach-msm/subsystem_map.c
index b5ff244..d6a17e6 100644
--- a/arch/arm/mach-msm/subsystem_map.c
+++ b/arch/arm/mach-msm/subsystem_map.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
@@ -34,6 +34,15 @@
static struct rb_root phys_root;
DEFINE_MUTEX(msm_buffer_mutex);
+static unsigned long subsystem_to_domain_tbl[] = {
+ VIDEO_DOMAIN,
+ VIDEO_DOMAIN,
+ CAMERA_DOMAIN,
+ DISPLAY_DOMAIN,
+ ROTATOR_DOMAIN,
+ 0xFFFFFFFF
+};
+
static struct msm_buffer_node *find_buffer(void *key)
{
struct rb_root *root = &buffer_root;
@@ -208,6 +217,31 @@
return 0;
}
+static unsigned long msm_subsystem_get_domain_no(int subsys_id)
+{
+ if (subsys_id > INVALID_SUBSYS_ID && subsys_id <= MAX_SUBSYSTEM_ID &&
+ subsys_id < ARRAY_SIZE(subsystem_to_domain_tbl))
+ return subsystem_to_domain_tbl[subsys_id];
+ else
+ return subsystem_to_domain_tbl[MAX_SUBSYSTEM_ID];
+}
+
+static unsigned long msm_subsystem_get_partition_no(int subsys_id)
+{
+ switch (subsys_id) {
+ case MSM_SUBSYSTEM_VIDEO_FWARE:
+ return VIDEO_FIRMWARE_POOL;
+ case MSM_SUBSYSTEM_VIDEO:
+ return VIDEO_MAIN_POOL;
+ case MSM_SUBSYSTEM_CAMERA:
+ case MSM_SUBSYSTEM_DISPLAY:
+ case MSM_SUBSYSTEM_ROTATOR:
+ return GEN_POOL;
+ default:
+ return 0xFFFFFFFF;
+ }
+}
+
phys_addr_t msm_subsystem_check_iova_mapping(int subsys_id, unsigned long iova)
{
struct iommu_domain *subsys_domain;
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index 47bc750..865fcc2 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -1303,15 +1303,15 @@
msm_rotator_dev->img_info[first_free_index];
*(msm_rotator_dev->img_info[first_free_index]) = info;
msm_rotator_dev->fd_info[first_free_index] = fd_info;
-
- if (copy_to_user((void __user *)arg, &info, sizeof(info)))
- rc = -EFAULT;
} else if (s == MAX_SESSIONS) {
dev_dbg(msm_rotator_dev->device, "%s: all sessions in use\n",
__func__);
rc = -EBUSY;
}
+ if (rc == 0 && copy_to_user((void __user *)arg, &info, sizeof(info)))
+ rc = -EFAULT;
+
rotator_start_exit:
mutex_unlock(&msm_rotator_dev->rotator_lock);
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 0cec423..6823a5a 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -484,7 +484,7 @@
valid_handle = ion_handle_validate(client, handle);
if (!valid_handle) {
mutex_unlock(&client->lock);
- WARN("%s: invalid handle passed to free.\n", __func__);
+ WARN(1, "%s: invalid handle passed to free.\n", __func__);
return;
}
ion_handle_put(handle);
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 7e84692..5faff24 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -122,6 +122,40 @@
}
/**
+ * kgsl_cancel_events_ctxt - Cancel all events for a context
+ * @device - KGSL device for the events to cancel
+ * @ctxt - context whose events we want to cancel
+ *
+ */
+static void kgsl_cancel_events_ctxt(struct kgsl_device *device,
+ struct kgsl_context *context)
+{
+ struct kgsl_event *event, *event_tmp;
+ unsigned int id, cur;
+
+ cur = device->ftbl->readtimestamp(device, context,
+ KGSL_TIMESTAMP_RETIRED);
+ id = context->id;
+
+ list_for_each_entry_safe(event, event_tmp, &device->events, list) {
+ if (event->context != context)
+ continue;
+
+ /*
+ * "cancel" the events by calling their callback.
+ * Currently, events are used for lock and memory
+ * management, so if the process is dying the right
+ * thing to do is release or free.
+ */
+ if (event->func)
+ event->func(device, event->priv, id, cur);
+
+ list_del(&event->list);
+ kfree(event);
+ }
+}
+
+/**
* kgsl_cancel_events - Cancel all events for a process
* @device - KGSL device for the events to cancel
* @owner - driver instance that owns the events to cancel
@@ -1240,6 +1274,8 @@
goto done;
}
+ kgsl_cancel_events_ctxt(dev_priv->device, context);
+
if (dev_priv->device->ftbl->drawctxt_destroy)
dev_priv->device->ftbl->drawctxt_destroy(dev_priv->device,
context);
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 7eb5ee9..8077323e 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -36,7 +36,8 @@
{
int i;
/* For IOMMU only unmap the global structures to global pt */
- if ((KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type) &&
+ if ((KGSL_MMU_TYPE_NONE != kgsl_mmu_type) &&
+ (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type) &&
(KGSL_MMU_GLOBAL_PT != pt->name))
return 0;
for (i = 0; i < KGSL_DEVICE_MAX; i++) {
@@ -47,6 +48,36 @@
return 0;
}
+
+static int kgsl_setup_pt(struct kgsl_pagetable *pt)
+{
+ int i = 0;
+ int status = 0;
+
+ /* For IOMMU only map the global structures to global pt */
+ if ((KGSL_MMU_TYPE_NONE != kgsl_mmu_type) &&
+ (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type) &&
+ (KGSL_MMU_GLOBAL_PT != pt->name))
+ return 0;
+ for (i = 0; i < KGSL_DEVICE_MAX; i++) {
+ struct kgsl_device *device = kgsl_driver.devp[i];
+ if (device) {
+ status = device->ftbl->setup_pt(device, pt);
+ if (status)
+ goto error_pt;
+ }
+ }
+ return status;
+error_pt:
+ while (i >= 0) {
+ struct kgsl_device *device = kgsl_driver.devp[i];
+ if (device)
+ device->ftbl->cleanup_pt(device, pt);
+ i--;
+ }
+ return status;
+}
+
static void kgsl_destroy_pagetable(struct kref *kref)
{
struct kgsl_pagetable *pagetable = container_of(kref,
@@ -340,9 +371,15 @@
mmu->device = device;
if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type) {
- dev_info(device->dev, "|%s| MMU type set for device is "
- "NOMMU\n", __func__);
- return 0;
+ int status = 0;
+ status = kgsl_allocate_contiguous(&mmu->setstate_memory, 64);
+ if (!status) {
+ kgsl_sharedmem_set(&mmu->setstate_memory, 0, 0,
+ mmu->setstate_memory.size);
+ dev_info(device->dev, "|%s| MMU type set for device is "
+ "NOMMU\n", __func__);
+ }
+ return status;
} else if (KGSL_MMU_TYPE_GPU == kgsl_mmu_type)
mmu->mmu_ops = &gpummu_ops;
else if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type)
@@ -358,6 +395,9 @@
if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) {
kgsl_regwrite(device, MH_MMU_CONFIG, 0);
+ /* Setup gpuaddr of global mappings */
+ if (!mmu->setstate_memory.gpuaddr)
+ kgsl_setup_pt(NULL);
return 0;
} else {
return mmu->mmu_ops->mmu_start(device);
@@ -385,34 +425,6 @@
}
EXPORT_SYMBOL(kgsl_mh_intrcallback);
-static int kgsl_setup_pt(struct kgsl_pagetable *pt)
-{
- int i = 0;
- int status = 0;
-
- /* For IOMMU only map the global structures to global pt */
- if ((KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type) &&
- (KGSL_MMU_GLOBAL_PT != pt->name))
- return 0;
- for (i = 0; i < KGSL_DEVICE_MAX; i++) {
- struct kgsl_device *device = kgsl_driver.devp[i];
- if (device) {
- status = device->ftbl->setup_pt(device, pt);
- if (status)
- goto error_pt;
- }
- }
- return status;
-error_pt:
- while (i >= 0) {
- struct kgsl_device *device = kgsl_driver.devp[i];
- if (device)
- device->ftbl->cleanup_pt(device, pt);
- i--;
- }
- return status;
-}
-
static struct kgsl_pagetable *kgsl_mmu_createpagetableobject(
unsigned int name)
{
@@ -589,7 +601,14 @@
if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) {
if (memdesc->sglen == 1) {
- memdesc->gpuaddr = sg_phys(memdesc->sg);
+ memdesc->gpuaddr = sg_dma_address(memdesc->sg);
+ if (!memdesc->gpuaddr)
+ memdesc->gpuaddr = sg_phys(memdesc->sg);
+ if (!memdesc->gpuaddr) {
+ KGSL_CORE_ERR("Unable to get a valid physical "
+ "address for memdesc\n");
+ return -EINVAL;
+ }
return 0;
} else {
KGSL_CORE_ERR("Memory is not contigious "
@@ -741,9 +760,10 @@
{
struct kgsl_mmu *mmu = &device->mmu;
- if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE)
+ if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) {
+ kgsl_sharedmem_free(&mmu->setstate_memory);
return 0;
- else
+ } else
return mmu->mmu_ops->mmu_close(device);
}
EXPORT_SYMBOL(kgsl_mmu_close);
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 3dea4e9..4fd6e49 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -3,10 +3,10 @@
CFLAGS_REMOVE_msm_vfe8x.o = -Wframe-larger-than=1024
endif
+EXTRA_CFLAGS += -Idrivers/media/video/msm/io
obj-$(CONFIG_MSM_CAMERA) += io/
ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
EXTRA_CFLAGS += -Idrivers/media/video/msm/csi
- EXTRA_CFLAGS += -Idrivers/media/video/msm/io
EXTRA_CFLAGS += -Idrivers/media/video/msm/sensors
obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o
obj-$(CONFIG_MSM_CAMERA) += sensors/ actuators/ csi/
diff --git a/drivers/media/video/msm/gemini/msm_gemini_platform.c b/drivers/media/video/msm/gemini/msm_gemini_platform.c
index ee0ff2f..fb5b035 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_platform.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_platform.c
@@ -20,6 +20,7 @@
#include <mach/msm_subsystem_map.h>
#include "msm_gemini_platform.h"
+#include "msm_gemini_sync.h"
#include "msm_gemini_common.h"
#include "msm_gemini_hw.h"
@@ -80,6 +81,20 @@
return 0;
}
+static struct msm_cam_clk_info gemini_8x_clk_info[] = {
+ {"ijpeg_clk", 228571000},
+ {"ijpeg_pclk", -1},
+};
+
+static struct msm_cam_clk_info gemini_7x_clk_info[] = {
+ {"jpeg_clk", 153600000},
+ {"jpeg_pclk", -1},
+};
+
+static struct msm_cam_clk_info gemini_imem_clk_info[] = {
+ {"imem_clk", -1},
+};
+
int msm_gemini_platform_init(struct platform_device *pdev,
struct resource **mem,
void **base,
@@ -91,6 +106,8 @@
int gemini_irq;
struct resource *gemini_mem, *gemini_io, *gemini_irq_res;
void *gemini_base;
+ struct msm_gemini_device *pgmn_dev =
+ (struct msm_gemini_device *) context;
gemini_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!gemini_mem) {
@@ -119,10 +136,43 @@
goto fail1;
}
- rc = msm_camio_jpeg_clk_enable();
- if (rc) {
- GMN_PR_ERR("%s: clk failed rc = %d\n", __func__, rc);
- goto fail2;
+ pgmn_dev->hw_version = GEMINI_8X60;
+ rc = msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_8x_clk_info,
+ pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_8x_clk_info), 1);
+ if (rc < 0) {
+ pgmn_dev->hw_version = GEMINI_7X;
+ rc = msm_cam_clk_enable(&pgmn_dev->pdev->dev,
+ gemini_7x_clk_info, pgmn_dev->gemini_clk,
+ ARRAY_SIZE(gemini_7x_clk_info), 1);
+ if (rc < 0) {
+ GMN_PR_ERR("%s: clk failed rc = %d\n", __func__, rc);
+ goto fail2;
+ }
+ } else {
+ rc = msm_cam_clk_enable(&pgmn_dev->pdev->dev,
+ gemini_imem_clk_info, &pgmn_dev->gemini_clk[2],
+ ARRAY_SIZE(gemini_imem_clk_info), 1);
+ if (!rc)
+ pgmn_dev->hw_version = GEMINI_8960;
+ }
+
+ if (pgmn_dev->hw_version != GEMINI_7X) {
+ if (pgmn_dev->gemini_fs == NULL) {
+ pgmn_dev->gemini_fs =
+ regulator_get(&pgmn_dev->pdev->dev, "fs_ijpeg");
+ if (IS_ERR(pgmn_dev->gemini_fs)) {
+ pr_err("%s: Regulator FS_ijpeg get failed %ld\n",
+ __func__, PTR_ERR(pgmn_dev->gemini_fs));
+ pgmn_dev->gemini_fs = NULL;
+ goto gemini_fs_failed;
+ } else if (regulator_enable(pgmn_dev->gemini_fs)) {
+ pr_err("%s: Regulator FS_ijpeg enable failed\n",
+ __func__);
+ regulator_put(pgmn_dev->gemini_fs);
+ pgmn_dev->gemini_fs = NULL;
+ goto gemini_fs_failed;
+ }
+ }
}
msm_gemini_hw_init(gemini_base, resource_size(gemini_mem));
@@ -146,7 +196,21 @@
return rc;
fail3:
- msm_camio_jpeg_clk_disable();
+ if (pgmn_dev->hw_version != GEMINI_7X) {
+ regulator_disable(pgmn_dev->gemini_fs);
+ regulator_put(pgmn_dev->gemini_fs);
+ pgmn_dev->gemini_fs = NULL;
+ }
+gemini_fs_failed:
+ if (pgmn_dev->hw_version == GEMINI_8960)
+ msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_imem_clk_info,
+ &pgmn_dev->gemini_clk[2], ARRAY_SIZE(gemini_imem_clk_info), 0);
+ if (pgmn_dev->hw_version != GEMINI_7X)
+ msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_8x_clk_info,
+ pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_8x_clk_info), 0);
+ else
+ msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_7x_clk_info,
+ pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_7x_clk_info), 0);
fail2:
iounmap(gemini_base);
fail1:
@@ -158,10 +222,28 @@
int msm_gemini_platform_release(struct resource *mem, void *base, int irq,
void *context)
{
- int result;
+ int result = 0;
+ struct msm_gemini_device *pgmn_dev =
+ (struct msm_gemini_device *) context;
free_irq(irq, context);
- result = msm_camio_jpeg_clk_disable();
+
+ if (pgmn_dev->hw_version != GEMINI_7X) {
+ regulator_disable(pgmn_dev->gemini_fs);
+ regulator_put(pgmn_dev->gemini_fs);
+ pgmn_dev->gemini_fs = NULL;
+ }
+
+ if (pgmn_dev->hw_version == GEMINI_8960)
+ msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_imem_clk_info,
+ &pgmn_dev->gemini_clk[2], ARRAY_SIZE(gemini_imem_clk_info), 0);
+ if (pgmn_dev->hw_version != GEMINI_7X)
+ msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_8x_clk_info,
+ pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_8x_clk_info), 0);
+ else
+ msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_7x_clk_info,
+ pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_7x_clk_info), 0);
+
iounmap(base);
release_mem_region(mem->start, resource_size(mem));
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
diff --git a/drivers/media/video/msm/gemini/msm_gemini_sync.h b/drivers/media/video/msm/gemini/msm_gemini_sync.h
index a47e766..1c6726d 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_sync.h
+++ b/drivers/media/video/msm/gemini/msm_gemini_sync.h
@@ -21,6 +21,10 @@
#include <media/v4l2-subdev.h>
#include "msm_gemini_core.h"
+#define GEMINI_7X 0x1
+#define GEMINI_8X60 (0x1 << 1)
+#define GEMINI_8960 (0x1 << 2)
+
struct msm_gemini_q {
char const *name;
struct list_head q;
@@ -39,6 +43,9 @@
struct resource *mem;
int irq;
void *base;
+ struct clk *gemini_clk[3];
+ struct regulator *gemini_fs;
+ uint32_t hw_version;
struct device *device;
struct cdev cdev;
diff --git a/drivers/media/video/msm/io/msm_io_8960.c b/drivers/media/video/msm/io/msm_io_8960.c
index 1ab4223..f9c454a 100644
--- a/drivers/media/video/msm/io/msm_io_8960.c
+++ b/drivers/media/video/msm/io/msm_io_8960.c
@@ -27,141 +27,11 @@
#define BUFF_SIZE_128 128
-static struct clk *camio_jpeg_clk;
-static struct clk *camio_jpeg_pclk;
-static struct clk *camio_imem_clk;
-static struct regulator *fs_ijpeg;
-
-int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
-{
- int rc = 0;
- struct clk *clk = NULL;
-
- switch (clktype) {
- case CAMIO_JPEG_CLK:
- camio_jpeg_clk =
- clk = clk_get(NULL, "ijpeg_clk");
- clk_set_rate(clk, 228571000);
- break;
-
- case CAMIO_JPEG_PCLK:
- camio_jpeg_pclk =
- clk = clk_get(NULL, "ijpeg_pclk");
- break;
-
- case CAMIO_IMEM_CLK:
- camio_imem_clk =
- clk = clk_get(NULL, "imem_clk");
- break;
-
- default:
- break;
- }
-
- if (!IS_ERR(clk))
- rc = clk_enable(clk);
- else
- rc = PTR_ERR(clk);
-
- if (rc < 0)
- pr_err("%s(%d) failed %d\n", __func__, clktype, rc);
-
- return rc;
-}
-
-int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
-{
- int rc = 0;
- struct clk *clk = NULL;
-
- switch (clktype) {
- case CAMIO_JPEG_CLK:
- clk = camio_jpeg_clk;
- break;
-
- case CAMIO_JPEG_PCLK:
- clk = camio_jpeg_pclk;
- break;
-
- case CAMIO_IMEM_CLK:
- clk = camio_imem_clk;
- break;
-
- default:
- break;
- }
-
- if (!IS_ERR(clk)) {
- clk_disable(clk);
- clk_put(clk);
- } else
- rc = PTR_ERR(clk);
-
- if (rc < 0)
- pr_err("%s(%d) failed %d\n", __func__, clktype, rc);
-
- return rc;
-}
-
void msm_camio_clk_rate_set_2(struct clk *clk, int rate)
{
clk_set_rate(clk, rate);
}
-int msm_camio_jpeg_clk_disable(void)
-{
- int rc = 0;
- rc = msm_camio_clk_disable(CAMIO_JPEG_PCLK);
- if (rc < 0)
- return rc;
- rc = msm_camio_clk_disable(CAMIO_JPEG_CLK);
- if (rc < 0)
- return rc;
- rc = msm_camio_clk_disable(CAMIO_IMEM_CLK);
- if (rc < 0)
- return rc;
-
- if (fs_ijpeg) {
- rc = regulator_disable(fs_ijpeg);
- if (rc < 0) {
- pr_err("%s: Regulator disable failed %d\n",
- __func__, rc);
- return rc;
- }
- regulator_put(fs_ijpeg);
- }
- CDBG("%s: exit %d\n", __func__, rc);
- return rc;
-}
-
-int msm_camio_jpeg_clk_enable(void)
-{
- int rc = 0;
- fs_ijpeg = regulator_get(NULL, "fs_ijpeg");
- if (IS_ERR(fs_ijpeg)) {
- pr_err("%s: Regulator FS_IJPEG get failed %ld\n",
- __func__, PTR_ERR(fs_ijpeg));
- fs_ijpeg = NULL;
- } else if (regulator_enable(fs_ijpeg)) {
- pr_err("%s: Regulator FS_IJPEG enable failed\n", __func__);
- regulator_put(fs_ijpeg);
- }
-
- rc = msm_camio_clk_enable(CAMIO_JPEG_CLK);
- if (rc < 0)
- return rc;
- rc = msm_camio_clk_enable(CAMIO_JPEG_PCLK);
- if (rc < 0)
- return rc;
-
- rc = msm_camio_clk_enable(CAMIO_IMEM_CLK);
- if (rc < 0)
- return rc;
-
- CDBG("%s: exit %d\n", __func__, rc);
- return rc;
-}
-
void msm_camio_bus_scale_cfg(struct msm_bus_scale_pdata *cam_bus_scale_table,
enum msm_bus_perf_setting perf_setting)
{
diff --git a/drivers/media/video/msm/io/msm_io_8x60.c b/drivers/media/video/msm/io/msm_io_8x60.c
index 4e8dc25..baa1245 100644
--- a/drivers/media/video/msm/io/msm_io_8x60.c
+++ b/drivers/media/video/msm/io/msm_io_8x60.c
@@ -85,12 +85,9 @@
static struct clk *camio_csi0_pclk;
static struct clk *camio_csi1_pclk;
static struct clk *camio_vfe_pclk;
-static struct clk *camio_jpeg_clk;
-static struct clk *camio_jpeg_pclk;
static struct clk *camio_vpe_clk;
static struct clk *camio_vpe_pclk;
static struct regulator *fs_vfe;
-static struct regulator *fs_ijpeg;
static struct regulator *fs_vpe;
static struct regulator *ldo15;
static struct regulator *lvs0;
@@ -254,17 +251,6 @@
clk = clk_get(&camio_dev->dev, "csi_pclk");
break;
- case CAMIO_JPEG_CLK:
- camio_jpeg_clk =
- clk = clk_get(NULL, "ijpeg_clk");
- msm_camio_clk_rate_set_2(clk, 228571000);
- break;
-
- case CAMIO_JPEG_PCLK:
- camio_jpeg_pclk =
- clk = clk_get(NULL, "ijpeg_pclk");
- break;
-
case CAMIO_VPE_CLK:
camio_vpe_clk =
clk = clk_get(NULL, "vpe_clk");
@@ -334,14 +320,6 @@
clk = camio_csi1_pclk;
break;
- case CAMIO_JPEG_CLK:
- clk = camio_jpeg_clk;
- break;
-
- case CAMIO_JPEG_PCLK:
- clk = camio_jpeg_pclk;
- break;
-
case CAMIO_VPE_CLK:
clk = camio_vpe_clk;
break;
@@ -393,47 +371,6 @@
return IRQ_HANDLED;
}
-int msm_camio_jpeg_clk_disable(void)
-{
- int rc = 0;
- if (fs_ijpeg) {
- rc = regulator_disable(fs_ijpeg);
- if (rc < 0) {
- CDBG("%s: Regulator disable failed %d\n", __func__, rc);
- return rc;
- }
- regulator_put(fs_ijpeg);
- }
- rc = msm_camio_clk_disable(CAMIO_JPEG_PCLK);
- if (rc < 0)
- return rc;
- rc = msm_camio_clk_disable(CAMIO_JPEG_CLK);
- CDBG("%s: exit %d\n", __func__, rc);
- return rc;
-}
-
-int msm_camio_jpeg_clk_enable(void)
-{
- int rc = 0;
- rc = msm_camio_clk_enable(CAMIO_JPEG_CLK);
- if (rc < 0)
- return rc;
- rc = msm_camio_clk_enable(CAMIO_JPEG_PCLK);
- if (rc < 0)
- return rc;
- fs_ijpeg = regulator_get(NULL, "fs_ijpeg");
- if (IS_ERR(fs_ijpeg)) {
- CDBG("%s: Regulator FS_IJPEG get failed %ld\n", __func__,
- PTR_ERR(fs_ijpeg));
- fs_ijpeg = NULL;
- } else if (regulator_enable(fs_ijpeg)) {
- CDBG("%s: Regulator FS_IJPEG enable failed\n", __func__);
- regulator_put(fs_ijpeg);
- }
- CDBG("%s: exit %d\n", __func__, rc);
- return rc;
-}
-
int msm_camio_vpe_clk_disable(void)
{
int rc = 0;
diff --git a/drivers/media/video/msm/io/msm_io_vfe31.c b/drivers/media/video/msm/io/msm_io_vfe31.c
index 7f3b7ae..24bba59 100644
--- a/drivers/media/video/msm/io/msm_io_vfe31.c
+++ b/drivers/media/video/msm/io/msm_io_vfe31.c
@@ -108,8 +108,6 @@
static struct clk *camio_csi_clk;
static struct clk *camio_csi_pclk;
static struct clk *camio_csi_vfe_clk;
-static struct clk *camio_jpeg_clk;
-static struct clk *camio_jpeg_pclk;
static struct clk *camio_vpe_clk;
static struct regulator *fs_vpe;
static struct msm_camera_io_ext camio_ext;
@@ -117,7 +115,6 @@
static struct resource *camifpadio, *csiio;
void __iomem *camifpadbase, *csibase;
static uint32_t vpe_clk_rate;
-static uint32_t jpeg_clk_rate;
static struct regulator_bulk_data regs[] = {
{ .supply = "gp2", .min_uV = 2600000, .max_uV = 2600000 },
@@ -239,16 +236,6 @@
clk = clk_get(NULL, "csi_pclk");
break;
- case CAMIO_JPEG_CLK:
- camio_jpeg_clk =
- clk = clk_get(NULL, "jpeg_clk");
- jpeg_clk_rate = clk_round_rate(clk, 144000000);
- clk_set_rate(clk, jpeg_clk_rate);
- break;
- case CAMIO_JPEG_PCLK:
- camio_jpeg_pclk =
- clk = clk_get(NULL, "jpeg_pclk");
- break;
case CAMIO_VPE_CLK:
camio_vpe_clk =
clk = clk_get(NULL, "vpe_clk");
@@ -308,12 +295,6 @@
case CAMIO_CSI0_PCLK:
clk = camio_csi_pclk;
break;
- case CAMIO_JPEG_CLK:
- clk = camio_jpeg_clk;
- break;
- case CAMIO_JPEG_PCLK:
- clk = camio_jpeg_pclk;
- break;
case CAMIO_VPE_CLK:
clk = camio_vpe_clk;
break;
@@ -356,22 +337,6 @@
return IRQ_HANDLED;
}
-int msm_camio_jpeg_clk_disable(void)
-{
- msm_camio_clk_disable(CAMIO_JPEG_CLK);
- msm_camio_clk_disable(CAMIO_JPEG_PCLK);
- /* Need to add the code for remove PM QOS requirement */
- return 0;
-}
-
-
-int msm_camio_jpeg_clk_enable(void)
-{
- msm_camio_clk_enable(CAMIO_JPEG_CLK);
- msm_camio_clk_enable(CAMIO_JPEG_PCLK);
- return 0;
-}
-
int msm_camio_vpe_clk_disable(void)
{
msm_camio_clk_disable(CAMIO_VPE_CLK);
diff --git a/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c b/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c
index 451cb5a..a1270ea 100644
--- a/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c
+++ b/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c
@@ -33,12 +33,9 @@
#define BUFF_SIZE_128 128
-static struct clk *camio_jpeg_clk;
static struct clk *camio_vfe_clk;
-static struct clk *camio_jpeg_pclk;
static struct clk *camio_vpe_clk;
static struct clk *camio_vpe_pclk;
-static struct regulator *fs_ijpeg;
static struct regulator *fs_vpe;
static int vpe_clk_rate;
@@ -49,19 +46,6 @@
struct clk *clk = NULL;
switch (clktype) {
- case CAMIO_JPEG_CLK:
- camio_jpeg_clk =
- clk = clk_get(NULL, "ijpeg_clk");
- rc = clk_set_rate(clk, 228571000);
- if (rc < 0)
- rc = clk_set_rate(clk, 153600000);
- break;
-
- case CAMIO_JPEG_PCLK:
- camio_jpeg_pclk =
- clk = clk_get(NULL, "ijpeg_pclk");
- break;
-
case CAMIO_VPE_CLK:
camio_vpe_clk =
clk = clk_get(NULL, "vpe_clk");
@@ -93,14 +77,6 @@
struct clk *clk = NULL;
switch (clktype) {
- case CAMIO_JPEG_CLK:
- clk = camio_jpeg_clk;
- break;
-
- case CAMIO_JPEG_PCLK:
- clk = camio_jpeg_pclk;
- break;
-
case CAMIO_VPE_CLK:
clk = camio_vpe_clk;
break;
@@ -138,47 +114,6 @@
clk_set_rate(clk, rate);
}
-int msm_camio_jpeg_clk_disable(void)
-{
- int rc = 0;
- if (fs_ijpeg) {
- rc = regulator_disable(fs_ijpeg);
- if (rc < 0) {
- CDBG("%s: Regulator disable failed %d\n", __func__, rc);
- return rc;
- }
- regulator_put(fs_ijpeg);
- }
- rc = msm_camio_clk_disable(CAMIO_JPEG_PCLK);
- if (rc < 0)
- return rc;
- rc = msm_camio_clk_disable(CAMIO_JPEG_CLK);
- CDBG("%s: exit %d\n", __func__, rc);
- return rc;
-}
-
-int msm_camio_jpeg_clk_enable(void)
-{
- int rc = 0;
- rc = msm_camio_clk_enable(CAMIO_JPEG_CLK);
- if (rc < 0)
- return rc;
- rc = msm_camio_clk_enable(CAMIO_JPEG_PCLK);
- if (rc < 0)
- return rc;
- fs_ijpeg = regulator_get(NULL, "fs_ijpeg");
- if (IS_ERR(fs_ijpeg)) {
- CDBG("%s: Regulator FS_IJPEG get failed %ld\n", __func__,
- PTR_ERR(fs_ijpeg));
- fs_ijpeg = NULL;
- } else if (regulator_enable(fs_ijpeg)) {
- CDBG("%s: Regulator FS_IJPEG enable failed\n", __func__);
- regulator_put(fs_ijpeg);
- }
- CDBG("%s: exit %d\n", __func__, rc);
- return rc;
-}
-
int msm_camio_vpe_clk_disable(void)
{
int rc = 0;
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index 6443250..670d0f8 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -154,7 +154,10 @@
unsigned int *nplanes, unsigned long sizes[],
void *alloc_ctxs[])
{
- *nbuffers = 3;
+ *nbuffers += 2;
+ if (*nbuffers > VIDEO_MAX_FRAME)
+ return -EINVAL;
+
*nplanes = 1;
return 0;
}
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index e1a6ffd..318c319 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -4082,21 +4082,22 @@
};
#endif
-void msmsdcc_print_regs(const char *name, void __iomem *base,
- unsigned int no_of_regs)
+static void msmsdcc_print_regs(const char *name, void __iomem *base,
+ u32 phys_base, unsigned int no_of_regs)
{
unsigned int i;
if (!base)
return;
- pr_info("===== %s: Register Dumps @base=0x%x =====\n",
- name, (u32)base);
+
+ pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
+ " =====\n", name, phys_base, (u32)base);
for (i = 0; i < no_of_regs; i = i + 4) {
- pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
- (u32)readl_relaxed(base + i*4),
- (u32)readl_relaxed(base + ((i+1)*4)),
- (u32)readl_relaxed(base + ((i+2)*4)),
- (u32)readl_relaxed(base + ((i+3)*4)));
+ pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
+ (u32)readl_relaxed(base + i*4),
+ (u32)readl_relaxed(base + ((i+1)*4)),
+ (u32)readl_relaxed(base + ((i+2)*4)),
+ (u32)readl_relaxed(base + ((i+3)*4)));
}
}
@@ -4104,17 +4105,17 @@
{
/* Dump current state of SDCC clocks, power and irq */
pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
- (host->pwr ? "ON" : "OFF"));
+ (host->pwr ? "ON" : "OFF"));
pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
- mmc_hostname(host->mmc),
- (host->clks_on ? "ON" : "OFF"),
- (u32)clk_get_rate(host->clk));
+ mmc_hostname(host->mmc), (host->clks_on ? "ON" : "OFF"),
+ (u32)clk_get_rate(host->clk));
pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
(host->sdcc_irq_disabled ? "disabled" : "enabled"));
/* Now dump SDCC registers. Don't print FIFO registers */
if (host->clks_on)
- msmsdcc_print_regs("SDCC-CORE", host->base, 28);
+ msmsdcc_print_regs("SDCC-CORE", host->base,
+ host->core_memres->start, 28);
if (host->curr.data) {
if (!msmsdcc_is_dma_possible(host, host->curr.data))
@@ -4123,22 +4124,27 @@
pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
mmc_hostname(host->mmc), host->dma.busy,
host->dma.channel, host->dma.crci);
- else if (host->is_sps_mode)
+ else if (host->is_sps_mode) {
+ if (host->sps.busy)
+ msmsdcc_print_regs("SDCC-DML", host->dml_base,
+ host->dml_memres->start,
+ 16);
pr_info("%s: SPS mode: busy=%d\n",
mmc_hostname(host->mmc), host->sps.busy);
+ }
pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
mmc_hostname(host->mmc), host->curr.xfer_size,
host->curr.data_xfered, host->curr.xfer_remain);
- pr_info("%s: got_dataend=%d, prog_enable=%d,"
- " wait_for_auto_prog_done=%d,"
- " got_auto_prog_done=%d\n",
- mmc_hostname(host->mmc), host->curr.got_dataend,
- host->prog_enable, host->curr.wait_for_auto_prog_done,
- host->curr.got_auto_prog_done);
}
+ pr_info("%s: got_dataend=%d, prog_enable=%d,"
+ " wait_for_auto_prog_done=%d, got_auto_prog_done=%d\n",
+ mmc_hostname(host->mmc), host->curr.got_dataend,
+ host->prog_enable, host->curr.wait_for_auto_prog_done,
+ host->curr.got_auto_prog_done);
}
+
static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
{
struct msmsdcc_host *host = (struct msmsdcc_host *)data;
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index ce748f5..aa1a589 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -78,9 +78,13 @@
/**
* struct pm8921_bms_chip -
* @bms_output_lock: lock to prevent concurrent bms reads
- * @bms_100_lock: lock to prevent concurrent updates to values that force
- * 100% charge
*
+ * @last_ocv_uv_mutex: mutex to protect simultaneous invocations of calculate
+ * state of charge, note that last_ocv_uv could be
+ * changed as soc is adjusted. This mutex protects
+ * simultaneous updates of last_ocv_uv as well. This mutex
+ * also protects changes to *_at_100 variables used in
+ * faking 100% SOC.
*/
struct pm8921_bms_chip {
struct device *dev;
@@ -111,7 +115,6 @@
unsigned int pmic_bms_irq[PM_BMS_MAX_INTS];
DECLARE_BITMAP(enabled_irqs, PM_BMS_MAX_INTS);
struct mutex bms_output_lock;
- spinlock_t bms_100_lock;
struct single_row_lut *adjusted_fcc_temp_lut;
unsigned int charging_began;
unsigned int start_percent;
@@ -127,6 +130,8 @@
int amux_2_trim_delta;
uint16_t prev_last_good_ocv_raw;
unsigned int rconn_mohm;
+ struct mutex last_ocv_uv_mutex;
+ int last_ocv_uv;
};
static struct pm8921_bms_chip *the_chip;
@@ -144,7 +149,6 @@
module_param(last_charge_increase, int, 0644);
static int last_rbatt = -EINVAL;
-static int last_ocv_uv = -EINVAL;
static int last_soc = -EINVAL;
static int last_real_fcc_mah = -EINVAL;
static int last_real_fcc_batt_temp = -EINVAL;
@@ -163,7 +167,6 @@
};
module_param_cb(last_rbatt, &bms_param_ops, &last_rbatt, 0644);
-module_param_cb(last_ocv_uv, &bms_param_ops, &last_ocv_uv, 0644);
module_param_cb(last_soc, &bms_param_ops, &last_soc, 0644);
/*
@@ -957,16 +960,28 @@
adjust_pon_ocv_raw(chip, raw);
convert_vbatt_raw_to_uv(chip, usb_chg,
raw->last_good_ocv_raw, &raw->last_good_ocv_uv);
- last_ocv_uv = raw->last_good_ocv_uv;
+ chip->last_ocv_uv = raw->last_good_ocv_uv;
} else if (chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
convert_vbatt_raw_to_uv(chip, usb_chg,
raw->last_good_ocv_raw, &raw->last_good_ocv_uv);
- last_ocv_uv = raw->last_good_ocv_uv;
+ chip->last_ocv_uv = raw->last_good_ocv_uv;
} else {
- raw->last_good_ocv_uv = last_ocv_uv;
+ raw->last_good_ocv_uv = chip->last_ocv_uv;
}
+ /* fake a high OCV if we are just done charging */
+ if (chip->ocv_reading_at_100 != raw->last_good_ocv_raw) {
+ chip->ocv_reading_at_100 = 0;
+ chip->cc_reading_at_100 = 0;
+ } else {
+ /*
+ * force 100% ocv by selecting the highest voltage the
+ * battery could ever reach
+ */
+ raw->last_good_ocv_uv = chip->max_voltage_uv;
+ chip->last_ocv_uv = chip->max_voltage_uv;
+ }
pr_debug("0p625 = %duV\n", chip->xoadc_v0625);
pr_debug("1p25 = %duV\n", chip->xoadc_v125);
pr_debug("last_good_ocv_raw= 0x%x, last_good_ocv_uv= %duV\n",
@@ -1120,7 +1135,7 @@
cc_voltage_uv = cc;
cc_voltage_uv -= chip->cc_reading_at_100;
- pr_debug("cc = %d. after subtracting %d cc = %lld\n",
+ pr_debug("cc = %d. after subtracting 0x%x cc = %lld\n",
cc, chip->cc_reading_at_100,
cc_voltage_uv);
cc_voltage_uv = cc_to_microvolt(chip, cc_voltage_uv);
@@ -1156,25 +1171,7 @@
{
int ocv, pc;
- /* calculate remainging charge */
- ocv = 0;
- if (chip->ocv_reading_at_100 != raw->last_good_ocv_raw) {
- chip->ocv_reading_at_100 = 0;
- chip->cc_reading_at_100 = 0;
- ocv = raw->last_good_ocv_uv;
- } else {
- /*
- * force 100% ocv by selecting the highest voltage the
- * battery could every reach
- */
- ocv = chip->max_voltage_uv;
- }
-
- if (ocv == 0) {
- ocv = last_ocv_uv;
- pr_debug("ocv not available using last_ocv_uv=%d\n", ocv);
- }
-
+ ocv = raw->last_good_ocv_uv;
pc = calculate_pc(chip, ocv, batt_temp, chargecycles);
pr_debug("ocv = %d pc = %d\n", ocv, pc);
return (fcc_uah * pc) / 100;
@@ -1189,7 +1186,6 @@
int *cc_uah,
int *rbatt)
{
- unsigned long flags;
int soc_rbatt;
*fcc_uah = calculate_fcc_uah(chip, batt_temp, chargecycles);
@@ -1197,7 +1193,6 @@
*fcc_uah, batt_temp, chargecycles);
- spin_lock_irqsave(&chip->bms_100_lock, flags);
/* calculate remainging charge */
*remaining_charge_uah = calculate_remaining_charge_uah(chip, raw,
*fcc_uah, batt_temp, chargecycles);
@@ -1205,11 +1200,10 @@
/* calculate cc micro_volt_hour */
calculate_cc_uah(chip, raw->cc, cc_uah);
- pr_debug("cc_uah = %duAh raw->cc = %x cc = %lld after subtracting %d\n",
+ pr_debug("cc_uah = %duAh raw->cc = %x cc = %lld after subtracting %x\n",
*cc_uah, raw->cc,
(int64_t)raw->cc - chip->cc_reading_at_100,
chip->cc_reading_at_100);
- spin_unlock_irqrestore(&chip->bms_100_lock, flags);
soc_rbatt = ((*remaining_charge_uah - *cc_uah) * 100) / *fcc_uah;
if (soc_rbatt < 0)
@@ -1245,6 +1239,108 @@
real_fcc_uah, remaining_charge_uah, cc_uah, fcc_uah);
return real_fcc_uah;
}
+
+static int bound_soc(int soc)
+{
+ soc = max(0, soc);
+ soc = min(100, soc);
+ return soc;
+}
+
+static int last_soc_est = -EINVAL;
+static int adjust_soc(struct pm8921_bms_chip *chip, int soc, int batt_temp,
+ int rbatt , int fcc_uah, int uuc_uah, int cc_uah)
+{
+ int ibat_ua = 0, vbat_uv = 0;
+ int ocv_est_uv = 0, soc_est = 0, pc_est = 0, pc = 0;
+ int delta_ocv_uv = 0;
+ int n = 0;
+ int rc_new_uah = 0;
+ int pc_new = 0;
+ int soc_new = 0;
+ int m = 0;
+
+ pm8921_bms_get_simultaneous_battery_voltage_and_current(&ibat_ua,
+ &vbat_uv);
+
+ if (ibat_ua < 0)
+ goto out;
+ ocv_est_uv = vbat_uv + (ibat_ua * rbatt)/1000;
+ pc_est = calculate_pc(chip, ocv_est_uv, batt_temp, last_chargecycles);
+ soc_est = div_s64((s64)fcc_uah * pc_est - uuc_uah*100,
+ (s64)fcc_uah - uuc_uah);
+ soc_est = bound_soc(soc_est);
+
+ /*
+ * do not adjust if soc_est is between 45 and 25 OR soc_est is
+ * same as what bms calculated
+ */
+ if (is_between(45, 25, soc_est) || soc_est == soc)
+ goto out;
+
+ if (last_soc_est == -EINVAL)
+ last_soc_est = soc;
+
+ n = min(200, max(1 , soc + soc_est + last_soc_est));
+ /* remember the last soc_est in last_soc_est */
+ last_soc_est = soc_est;
+
+ pc = calculate_pc(chip, chip->last_ocv_uv,
+ batt_temp, last_chargecycles);
+ if (pc > 0) {
+ pc_new = calculate_pc(chip, chip->last_ocv_uv - (++m * 1000),
+ batt_temp, last_chargecycles);
+ while (pc_new == pc) {
+ /* start taking 10mV steps */
+ m = m + 10;
+ pc_new = calculate_pc(chip,
+ chip->last_ocv_uv - (m * 1000),
+ batt_temp, last_chargecycles);
+ }
+ } else {
+ /*
+ * pc is already at the lowest point,
+ * assume 1 millivolt translates to 1% pc
+ */
+ pc = 1;
+ pc_new = 0;
+ m = 1;
+ }
+
+ delta_ocv_uv = div_s64((soc - soc_est) * (s64)m * 1000,
+ n * (pc - pc_new));
+ chip->last_ocv_uv -= delta_ocv_uv;
+
+ if (chip->last_ocv_uv >= chip->max_voltage_uv)
+ chip->last_ocv_uv = chip->max_voltage_uv;
+
+ /* calculate the soc based on this new ocv */
+ pc_new = calculate_pc(chip, chip->last_ocv_uv,
+ batt_temp, last_chargecycles);
+ rc_new_uah = (fcc_uah * pc_new) / 100;
+ soc_new = (rc_new_uah - cc_uah - uuc_uah)*100 / (fcc_uah - uuc_uah);
+ soc_new = bound_soc(soc_new);
+
+ /*
+ * if soc_new is ZERO force it higher so that phone doesnt report soc=0
+ * soc = 0 should happen only when soc_est == 0
+ */
+ if (soc_new == 0 && soc_est != 0)
+ soc_new = 1;
+
+ soc = soc_new;
+
+out:
+ pr_debug("ibat_ua = %d, vbat_uv = %d, ocv_est_uv = %d, pc_est = %d, "
+ "soc_est = %d, n = %d, delta_ocv_uv = %d, last_ocv_uv = %d, "
+ "pc_new = %d, soc_new = %d\n",
+ ibat_ua, vbat_uv, ocv_est_uv, pc_est,
+ soc_est, n, delta_ocv_uv, chip->last_ocv_uv,
+ pc_new, soc_new);
+
+ return soc;
+}
+
/*
* Remaining Usable Charge = remaining_charge (charge at ocv instance)
* - coloumb counter charge
@@ -1257,7 +1353,6 @@
{
int remaining_usable_charge_uah, fcc_uah, unusable_charge_uah;
int remaining_charge_uah, soc;
- int update_userspace = 1;
int cc_uah;
int rbatt;
@@ -1302,30 +1397,31 @@
pr_err("for bad rem_usb_chg last_ocv_uv = %d"
"chargecycles = %d, batt_temp = %d"
"fcc = %d soc =%d\n",
- last_ocv_uv, chargecycles, batt_temp,
+ chip->last_ocv_uv, chargecycles, batt_temp,
fcc_uah, soc);
- update_userspace = 0;
soc = 0;
}
- if (last_soc == -EINVAL || soc <= last_soc) {
- last_soc = update_userspace ? soc : last_soc;
- return soc;
- }
+ soc = adjust_soc(chip, soc, batt_temp, rbatt,
+ fcc_uah, unusable_charge_uah, cc_uah);
- /*
- * soc > last_soc
- * the device must be charging for reporting a higher soc, if not ignore
- * this soc and continue reporting the last_soc
- */
- if (the_chip->start_percent != -EINVAL) {
+ if (last_soc == -EINVAL || soc <= last_soc) {
last_soc = soc;
} else {
- pr_debug("soc = %d reporting last_soc = %d\n", soc, last_soc);
- soc = last_soc;
+ /*
+ * soc > last_soc
+ * the device must be charging for reporting a higher soc, if
+ * not ignore this soc and continue reporting the last_soc
+ */
+ if (the_chip->start_percent != -EINVAL)
+ last_soc = soc;
+ else
+ pr_debug("soc = %d reporting last_soc = %d\n", soc,
+ last_soc);
}
- return soc;
+ pr_debug("Reported SOC = %u%%\n", last_soc);
+ return last_soc;
}
#define MIN_DELTA_625_UV 1000
static void calib_hkadc(struct pm8921_bms_chip *chip)
@@ -1452,6 +1548,7 @@
int batt_temp, rc;
struct pm8xxx_adc_chan_result result;
struct pm8921_soc_params raw;
+ int soc;
if (!the_chip) {
pr_err("called before initialization\n");
@@ -1468,10 +1565,13 @@
result.measurement);
batt_temp = (int)result.physical;
+ mutex_lock(&the_chip->last_ocv_uv_mutex);
read_soc_params_raw(the_chip, &raw);
- return calculate_state_of_charge(the_chip, &raw,
+ soc = calculate_state_of_charge(the_chip, &raw,
batt_temp, last_chargecycles);
+ mutex_unlock(&the_chip->last_ocv_uv_mutex);
+ return soc;
}
EXPORT_SYMBOL_GPL(pm8921_bms_get_percent_charge);
@@ -1501,6 +1601,8 @@
result.measurement);
batt_temp = (int)result.physical;
+ mutex_lock(&the_chip->last_ocv_uv_mutex);
+
read_soc_params_raw(the_chip, &raw);
calculate_soc_params(the_chip, &raw, batt_temp, last_chargecycles,
@@ -1509,6 +1611,8 @@
&remaining_charge_uah,
&cc_uah,
&rbatt);
+ mutex_unlock(&the_chip->last_ocv_uv_mutex);
+
return rbatt;
}
EXPORT_SYMBOL_GPL(pm8921_bms_get_rbatt);
@@ -1556,10 +1660,13 @@
result.measurement);
batt_temp = (int)result.physical;
+ mutex_lock(&the_chip->last_ocv_uv_mutex);
read_soc_params_raw(the_chip, &raw);
the_chip->start_percent = calculate_state_of_charge(the_chip, &raw,
batt_temp, last_chargecycles);
+ mutex_unlock(&the_chip->last_ocv_uv_mutex);
+
bms_start_percent = the_chip->start_percent;
bms_start_ocv_uv = raw.last_good_ocv_uv;
calculate_cc_uah(the_chip, raw.cc, &bms_start_cc_uah);
@@ -1590,13 +1697,16 @@
result.measurement);
batt_temp = (int)result.physical;
+ mutex_lock(&the_chip->last_ocv_uv_mutex);
+
read_soc_params_raw(the_chip, &raw);
calculate_cc_uah(the_chip, raw.cc, &bms_end_cc_uah);
+ bms_end_ocv_uv = raw.last_good_ocv_uv;
+
if (is_battery_full
&& the_chip->start_percent <= MIN_START_PERCENT_FOR_LEARNING) {
- unsigned long flags;
int fcc_uah, new_fcc_uah, delta_fcc_uah;
new_fcc_uah = calculate_real_fcc_uah(the_chip, &raw,
@@ -1627,20 +1737,24 @@
last_real_fcc_batt_temp = batt_temp;
readjust_fcc_table();
- spin_lock_irqsave(&the_chip->bms_100_lock, flags);
+ }
+
+ if (is_battery_full) {
the_chip->ocv_reading_at_100 = raw.last_good_ocv_raw;
the_chip->cc_reading_at_100 = raw.cc;
- spin_unlock_irqrestore(&the_chip->bms_100_lock, flags);
- pr_debug("EOC ocv_reading = 0x%x cc = %d\n",
+
+ the_chip->last_ocv_uv = the_chip->max_voltage_uv;
+ raw.last_good_ocv_uv = the_chip->max_voltage_uv;
+ pr_debug("EOC ocv_reading = 0x%x cc = 0x%x\n",
the_chip->ocv_reading_at_100,
the_chip->cc_reading_at_100);
}
the_chip->end_percent = calculate_state_of_charge(the_chip, &raw,
batt_temp, last_chargecycles);
+ mutex_unlock(&the_chip->last_ocv_uv_mutex);
bms_end_percent = the_chip->end_percent;
- bms_end_ocv_uv = raw.last_good_ocv_uv;
if (the_chip->end_percent > the_chip->start_percent) {
last_charge_increase +=
@@ -1804,6 +1918,8 @@
chip->batt_temp_channel, rc);
}
chip->batt_temp_suspend = (int)result.physical;
+
+ mutex_lock(&chip->last_ocv_uv_mutex);
read_soc_params_raw(chip, &raw);
fcc_uah = calculate_fcc_uah(chip,
@@ -1818,12 +1934,14 @@
/* calculate cc micro_volt_hour */
calculate_cc_uah(chip, raw.cc, &cc_uah);
- pr_debug("cc_uah = %duAh raw->cc = %x cc = %lld after subtracting %d\n",
+ pr_debug("cc_uah = %duAh raw->cc = %x cc = %lld after subtracting %x\n",
cc_uah, raw.cc,
(int64_t)raw.cc - chip->cc_reading_at_100,
chip->cc_reading_at_100);
chip->soc_rbatt_suspend = ((remaining_charge_uah - cc_uah) * 100)
/ fcc_uah;
+ mutex_unlock(&chip->last_ocv_uv_mutex);
+
return 0;
}
@@ -1911,9 +2029,9 @@
pr_err("failed to read adc based ocv_uv rc = %d\n", rc);
ocv_uv = DEFAULT_OCV_MICROVOLTS;
}
- last_ocv_uv = ocv_uv;
}
- pr_debug("ocv_uv = %d last_ocv_uv = %d\n", ocv_uv, last_ocv_uv);
+ chip->last_ocv_uv = ocv_uv;
+ pr_debug("ocv_uv = %d last_ocv_uv = %d\n", ocv_uv, chip->last_ocv_uv);
}
static int64_t read_battery_id(struct pm8921_bms_chip *chip)
@@ -2314,8 +2432,9 @@
pr_err("Cannot allocate pm_bms_chip\n");
return -ENOMEM;
}
+
mutex_init(&chip->bms_output_lock);
- spin_lock_init(&chip->bms_100_lock);
+ mutex_init(&chip->last_ocv_uv_mutex);
chip->dev = &pdev->dev;
chip->r_sense = pdata->r_sense;
chip->i_test = pdata->i_test;
@@ -2387,7 +2506,7 @@
get_battery_uvolts(chip, &vbatt);
pr_info("OK battery_capacity_at_boot=%d volt = %d ocv = %d\n",
pm8921_bms_get_percent_charge(),
- vbatt, last_ocv_uv);
+ vbatt, chip->last_ocv_uv);
return 0;
free_irqs:
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index cc008ab..24da4d1 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -1978,6 +1978,9 @@
slc1 = ctrl->sched.chc1[coeff1];
}
}
+ /* Leave some slots for messaging space */
+ if (opensl1[1] == 0 && opensl1[0] == 0)
+ return -EXFULL;
if (opensl1[1] > opensl1[0]) {
int temp = opensl1[0];
opensl1[0] = opensl1[1];
@@ -2180,6 +2183,9 @@
slc1 = ctrl->sched.chc1[coeff1];
}
}
+ /* Leave some slots for messaging space */
+ if (opensl3[1] == 0 && opensl3[0] == 0)
+ return -EXFULL;
/* swap 1st and 2nd bucket if 2nd bucket has more open slots */
if (opensl3[1] > opensl3[0]) {
int temp = opensl3[0];
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index e2d77e9..69e0546 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -1155,6 +1155,22 @@
return xfrs_grped;
}
+static inline void write_force_cs(struct msm_spi *dd, bool set_flag)
+{
+ u32 spi_ioc;
+ u32 spi_ioc_orig;
+
+ spi_ioc = readl_relaxed(dd->base + SPI_IO_CONTROL);
+ spi_ioc_orig = spi_ioc;
+ if (set_flag)
+ spi_ioc |= SPI_IO_C_FORCE_CS;
+ else
+ spi_ioc &= ~SPI_IO_C_FORCE_CS;
+
+ if (spi_ioc != spi_ioc_orig)
+ writel_relaxed(spi_ioc, dd->base + SPI_IO_CONTROL);
+}
+
static void msm_spi_process_message(struct msm_spi *dd)
{
int xfrs_grped = 0;
@@ -1178,11 +1194,10 @@
}
if (dd->qup_ver) {
+ write_force_cs(dd, 0);
list_for_each_entry(dd->cur_transfer,
&dd->cur_msg->transfers,
transfer_list) {
- u32 spi_ioc;
- u32 spi_ioc_orig;
struct spi_transfer *t = dd->cur_transfer;
struct spi_transfer *nxt;
@@ -1191,18 +1206,10 @@
struct spi_transfer,
transfer_list);
- spi_ioc = readl_relaxed(dd->base +
- SPI_IO_CONTROL);
- spi_ioc_orig = spi_ioc;
if (t->cs_change == nxt->cs_change)
- spi_ioc |= SPI_IO_C_FORCE_CS;
+ write_force_cs(dd, 1);
else
- spi_ioc &= ~SPI_IO_C_FORCE_CS;
-
- if (spi_ioc != spi_ioc_orig) {
- writel_relaxed(spi_ioc,
- dd->base + SPI_IO_CONTROL);
- }
+ write_force_cs(dd, 0);
}
dd->cur_msg_len = dd->cur_transfer->len;
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index 578e339..b8d1df8 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -802,9 +802,18 @@
Support for HDMI CEC Feature
Choose to enable CEC
-config FB_MSM_HDMI_MHL
+config FB_MSM_HDMI_MHL_9244
depends on FB_MSM_HDMI_MSM_PANEL
- bool 'HDMI to MHL support'
+ bool 'SI_MHL 9244 support'
+ default n
+ ---help---
+ Support the HDMI to MHL conversion.
+ MHL (Mobile High-Definition Link) technology
+ uses USB connector to output HDMI content
+
+config FB_MSM_HDMI_MHL_8334
+ depends on FB_MSM_HDMI_MSM_PANEL
+ bool 'SI_MHL 8334 support '
default n
---help---
Support the HDMI to MHL conversion.
diff --git a/drivers/video/msm/Makefile b/drivers/video/msm/Makefile
index 5a72ad4..b2ecb08 100644
--- a/drivers/video/msm/Makefile
+++ b/drivers/video/msm/Makefile
@@ -171,6 +171,11 @@
obj-$(CONFIG_FB_MSM_TVOUT) += tvout_msm.o
+ccflags-y := -I$(src)/mhl
+obj-$(CONFIG_FB_MSM_HDMI_MHL_8334) += mhl-8334.o
+mhl-8334-objs += mhl/mhl_8334.o
+mhl-8334-objs += mhl/mhl_i2c_utils.o
+
obj-$(CONFIG_FB_MSM_EXTMDDI_SVGA) += mddi_ext_lcd.o
obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += mdp4_wfd_writeback_panel.o
diff --git a/drivers/video/msm/mhl/mhl_8334.c b/drivers/video/msm/mhl/mhl_8334.c
new file mode 100644
index 0000000..43280a5
--- /dev/null
+++ b/drivers/video/msm/mhl/mhl_8334.c
@@ -0,0 +1,849 @@
+/* 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/types.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <mach/msm_hdmi_audio.h>
+#include <mach/clk.h>
+#include <mach/msm_iomap.h>
+#include <mach/socinfo.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+#include "msm_fb.h"
+#include "external_common.h"
+#include "mhl_8334.h"
+#include "mhl_i2c_utils.h"
+
+#define DEBUG
+
+
+static struct i2c_device_id mhl_sii_i2c_id[] = {
+ { MHL_DRIVER_NAME, 0 },
+ { }
+};
+
+struct mhl_msm_state_t *mhl_msm_state;
+spinlock_t mhl_state_lock;
+
+static int mhl_i2c_probe(struct i2c_client *client,\
+ const struct i2c_device_id *id);
+static int mhl_i2c_remove(struct i2c_client *client);
+static void force_usb_switch_open(void);
+static void release_usb_switch_open(void);
+static void switch_mode(enum mhl_st_type to_mode);
+static irqreturn_t mhl_tx_isr(int irq, void *dev_id);
+
+static struct i2c_driver mhl_sii_i2c_driver = {
+ .driver = {
+ .name = MHL_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = mhl_i2c_probe,
+ /*.remove = __exit_p(mhl_i2c_remove),*/
+ .remove = mhl_i2c_remove,
+ .id_table = mhl_sii_i2c_id,
+};
+
+bool mhl_is_connected(void)
+{
+ return true;
+}
+
+static void cbus_reset(void)
+{
+ uint8_t i;
+
+ /*
+ * REG_SRST
+ */
+ mhl_i2c_reg_modify(TX_PAGE_3, 0x0000, BIT3, BIT3);
+ msleep(20);
+ mhl_i2c_reg_modify(TX_PAGE_3, 0x0000, BIT3, 0x00);
+ /*
+ * REG_INTR1 and REG_INTR4
+ */
+ mhl_i2c_reg_write(TX_PAGE_L0, 0x0075, BIT6 | BIT5);
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0022,
+ BIT0 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6);
+ /* REG5 */
+ if (mhl_msm_state->chip_rev_id < 1)
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0024, BIT3 | BIT4);
+ else
+ /*REG5 Mask disabled due to auto FIFO reset ??*/
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0024, 0x00);
+
+ /* Unmask CBUS1 Intrs */
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0009,
+ BIT2 | BIT3 | BIT4 | BIT5 | BIT6);
+
+ /* Unmask CBUS2 Intrs */
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x001F, BIT2 | BIT3);
+
+ for (i = 0; i < 4; i++) {
+ /*
+ * Enable WRITE_STAT interrupt for writes to
+ * all 4 MSC Status registers.
+ */
+ mhl_i2c_reg_write(TX_PAGE_CBUS, (0xE0 + i), 0xFF);
+
+ /*
+ * Enable SET_INT interrupt for writes to
+ * all 4 MSC Interrupt registers.
+ */
+ mhl_i2c_reg_write(TX_PAGE_CBUS, (0xF0 + i), 0xFF);
+ }
+}
+
+static void init_cbus_regs(void)
+{
+ uint8_t regval;
+
+ /* Increase DDC translation layer timer*/
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0007, 0xF2);
+ /* Drive High Time */
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0036, 0x03);
+ /* Use programmed timing */
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0039, 0x30);
+ /* CBUS Drive Strength */
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0040, 0x03);
+ /*
+ * Write initial default settings
+ * to devcap regs: default settings
+ */
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_DEV_STATE,
+ DEVCAP_VAL_DEV_STATE);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_MHL_VERSION,
+ DEVCAP_VAL_MHL_VERSION);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_DEV_CAT,
+ DEVCAP_VAL_DEV_CAT);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_ADOPTER_ID_H,
+ DEVCAP_VAL_ADOPTER_ID_H);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_ADOPTER_ID_L,
+ DEVCAP_VAL_ADOPTER_ID_L);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_VID_LINK_MODE,
+ DEVCAP_VAL_VID_LINK_MODE);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_AUD_LINK_MODE,
+ DEVCAP_VAL_AUD_LINK_MODE);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_VIDEO_TYPE,
+ DEVCAP_VAL_VIDEO_TYPE);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_LOG_DEV_MAP,
+ DEVCAP_VAL_LOG_DEV_MAP);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_BANDWIDTH,
+ DEVCAP_VAL_BANDWIDTH);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_FEATURE_FLAG,
+ DEVCAP_VAL_FEATURE_FLAG);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_DEVICE_ID_H,
+ DEVCAP_VAL_DEVICE_ID_H);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_DEVICE_ID_L,
+ DEVCAP_VAL_DEVICE_ID_L);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_SCRATCHPAD_SIZE,
+ DEVCAP_VAL_SCRATCHPAD_SIZE);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_INT_STAT_SIZE,
+ DEVCAP_VAL_INT_STAT_SIZE);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_RESERVED,
+ DEVCAP_VAL_RESERVED);
+
+ /* Make bits 2,3 (initiator timeout) to 1,1
+ * for register CBUS_LINK_CONTROL_2
+ * REG_CBUS_LINK_CONTROL_2
+ */
+ regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x0031);
+ regval = (regval | 0x0C);
+ /* REG_CBUS_LINK_CONTROL_2 */
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0031, regval);
+ /* REG_MSC_TIMEOUT_LIMIT */
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0022, 0x0F);
+ /* REG_CBUS_LINK_CONTROL_1 */
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0030, 0x01);
+ /* disallow vendor specific commands */
+ mhl_i2c_reg_modify(TX_PAGE_CBUS, 0x002E, BIT4, BIT4);
+}
+
+/*
+ * Configure the initial reg settings
+ */
+static void mhl_init_reg_settings(void)
+{
+
+ /*
+ * ============================================
+ * POWER UP
+ * ============================================
+ */
+
+ /* Power up 1.2V core */
+ mhl_i2c_reg_write(TX_PAGE_L1, 0x003D, 0x3F);
+ /* Enable Tx PLL Clock */
+ mhl_i2c_reg_write(TX_PAGE_2, 0x0011, 0x01);
+ /* Enable Tx Clock Path and Equalizer */
+ mhl_i2c_reg_write(TX_PAGE_2, 0x0012, 0x11);
+ /* Tx Source Termination ON */
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0030, 0x10);
+ /* Enable 1X MHL Clock output */
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0035, 0xAC);
+ /* Tx Differential Driver Config */
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0031, 0x3C);
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0033, 0xD9);
+ /* PLL Bandwidth Control */
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0037, 0x02);
+ /*
+ * ============================================
+ * Analog PLL Control
+ * ============================================
+ */
+ /* Enable Rx PLL clock */
+ mhl_i2c_reg_write(TX_PAGE_L0, 0x0080, 0x00);
+ mhl_i2c_reg_write(TX_PAGE_L0, 0x00F8, 0x0C);
+ mhl_i2c_reg_write(TX_PAGE_L0, 0x0085, 0x02);
+ mhl_i2c_reg_write(TX_PAGE_2, 0x0000, 0x00);
+ mhl_i2c_reg_write(TX_PAGE_2, 0x0013, 0x60);
+ /* PLL Cal ref sel */
+ mhl_i2c_reg_write(TX_PAGE_2, 0x0017, 0x03);
+ /* VCO Cal */
+ mhl_i2c_reg_write(TX_PAGE_2, 0x001A, 0x20);
+ /* Auto EQ */
+ mhl_i2c_reg_write(TX_PAGE_2, 0x0022, 0xE0);
+ mhl_i2c_reg_write(TX_PAGE_2, 0x0023, 0xC0);
+ mhl_i2c_reg_write(TX_PAGE_2, 0x0024, 0xA0);
+ mhl_i2c_reg_write(TX_PAGE_2, 0x0025, 0x80);
+ mhl_i2c_reg_write(TX_PAGE_2, 0x0026, 0x60);
+ mhl_i2c_reg_write(TX_PAGE_2, 0x0027, 0x40);
+ mhl_i2c_reg_write(TX_PAGE_2, 0x0028, 0x20);
+ mhl_i2c_reg_write(TX_PAGE_2, 0x0029, 0x00);
+ /* Rx PLL Bandwidth 4MHz */
+ mhl_i2c_reg_write(TX_PAGE_2, 0x0031, 0x0A);
+ /* Rx PLL Bandwidth value from I2C */
+ mhl_i2c_reg_write(TX_PAGE_2, 0x0045, 0x06);
+ mhl_i2c_reg_write(TX_PAGE_2, 0x004B, 0x06);
+ /* Manual zone control */
+ mhl_i2c_reg_write(TX_PAGE_2, 0x004C, 0xE0);
+ /* PLL Mode value */
+ mhl_i2c_reg_write(TX_PAGE_2, 0x004D, 0x00);
+ mhl_i2c_reg_write(TX_PAGE_L0, 0x0008, 0x35);
+ /*
+ * Discovery Control and Status regs
+ * Setting De-glitch time to 50 ms (default)
+ * Switch Control Disabled
+ */
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0011, 0xAD);
+ /* 1.8V CBUS VTH */
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0014, 0x55);
+ /* RGND and single Discovery attempt */
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0015, 0x11);
+ /* Ignore VBUS */
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0017, 0x82);
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0018, 0x24);
+ /* Pull-up resistance off for IDLE state */
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0013, 0x84);
+ /* Enable CBUS Discovery */
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0010, 0x27);
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0016, 0x20);
+ /* MHL CBUS Discovery - immediate comm. */
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0012, 0x86);
+ /* Do not force HPD to 0 during wake-up from D3 */
+ if (mhl_msm_state->cur_state != POWER_STATE_D3) {
+ mhl_i2c_reg_modify(TX_PAGE_3, 0x0020,
+ BIT5 | BIT4, BIT4);
+ }
+ /* Enable Auto Soft RESET */
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0000, 0x084);
+ /* HDMI Transcode mode enable */
+ mhl_i2c_reg_write(TX_PAGE_L0, 0x000D, 0x1C);
+
+ cbus_reset();
+ init_cbus_regs();
+}
+
+static int mhl_chip_init(void)
+{
+ /* Read the chip rev ID */
+ mhl_msm_state->chip_rev_id = mhl_i2c_reg_read(TX_PAGE_L0, 0x04);
+ pr_debug("MHL: chip rev ID read=[%x]\n", mhl_msm_state->chip_rev_id);
+
+ /* Reset the TX chip */
+ mhl_msm_state->mhl_data->reset_pin(0);
+ msleep(20);
+ mhl_msm_state->mhl_data->reset_pin(1);
+ /* MHL spec requires a 100 ms wait here. */
+ msleep(100);
+
+ mhl_init_reg_settings();
+
+ /*
+ * Power down the chip to the
+ * D3 - a low power standby mode
+ * cable impedance measurement logic is operational
+ */
+ switch_mode(POWER_STATE_D3);
+ return 0;
+}
+
+/*
+ * I2C probe
+ */
+static int mhl_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret;
+ mhl_msm_state->mhl_data = kzalloc(sizeof(struct msm_mhl_platform_data),
+ GFP_KERNEL);
+ if (!(mhl_msm_state->mhl_data)) {
+ ret = -ENOMEM;
+ goto probe_exit;
+ }
+ pr_debug("Inside probe\n");
+ mhl_msm_state->i2c_client = client;
+
+ spin_lock_init(&mhl_state_lock);
+
+ i2c_set_clientdata(client, mhl_msm_state);
+ mhl_msm_state->mhl_data = client->dev.platform_data;
+
+ /* Init GPIO stuff here */
+ ret = mhl_msm_state->mhl_data->gpio_setup(1);
+ if (ret == -1) {
+ pr_err("MHL: mhl_gpio_init has failed\n");
+ ret = -ENODEV;
+ goto probe_exit;
+ }
+ return 0;
+
+probe_exit:
+ if (mhl_msm_state->mhl_data) {
+ /* free the gpios */
+ mhl_msm_state->mhl_data->gpio_setup(0);
+ kfree(mhl_msm_state->mhl_data);
+ mhl_msm_state->mhl_data = NULL;
+ }
+ return ret;
+}
+
+static int mhl_i2c_remove(struct i2c_client *client)
+{
+ pr_debug("inside i2c remove\n");
+ mhl_msm_state->mhl_data->gpio_setup(0);
+ kfree(mhl_msm_state->mhl_data);
+ return 0;
+}
+
+static int __init mhl_msm_init(void)
+{
+ int32_t ret;
+
+ mhl_msm_state = kzalloc(sizeof(struct mhl_msm_state_t), GFP_KERNEL);
+ if (!mhl_msm_state) {
+ pr_err("mhl_msm_init FAILED: out of memory\n");
+ ret = -ENOMEM;
+ goto init_exit;
+ }
+
+ mhl_msm_state->i2c_client = NULL;
+ ret = i2c_add_driver(&mhl_sii_i2c_driver);
+ if (ret) {
+ pr_err("MHL: I2C driver add failed: %d\n", ret);
+ ret = -ENODEV;
+ goto init_exit;
+ } else {
+ if (mhl_msm_state->i2c_client == NULL) {
+ pr_err("JSR: I2C driver add failed\n");
+ ret = -ENODEV;
+ goto init_exit;
+ }
+ pr_debug("MHL: I2C driver added\n");
+ }
+
+ /* Request IRQ stuff here */
+ pr_debug("MHL: mhl_msm_state->mhl_data->irq=[%d]\n",
+ mhl_msm_state->mhl_data->irq);
+ ret = request_threaded_irq(mhl_msm_state->mhl_data->irq, NULL,
+ &mhl_tx_isr,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "mhl_tx_isr", mhl_msm_state);
+ if (ret != 0) {
+ pr_err("request_threaded_irq failed, status: %d\n",
+ ret);
+ ret = -EACCES; /* Error code???? */
+ goto init_exit;
+ }
+
+ mhl_msm_state->cur_state = POWER_STATE_D0_MHL;
+
+ /* MHL SII 8334 chip specific init */
+ mhl_chip_init();
+ return 0;
+
+init_exit:
+ pr_err("Exiting from the init with err\n");
+ i2c_del_driver(&mhl_sii_i2c_driver);
+ if (!mhl_msm_state) {
+ kfree(mhl_msm_state);
+ mhl_msm_state = NULL;
+ }
+ return ret;
+}
+
+static void switch_mode(enum mhl_st_type to_mode)
+{
+ unsigned long flags;
+
+ switch (to_mode) {
+ case POWER_STATE_D0_NO_MHL:
+ break;
+ case POWER_STATE_D0_MHL:
+ mhl_init_reg_settings();
+
+ /* REG_DISC_CTRL1 */
+ mhl_i2c_reg_modify(TX_PAGE_3, 0x0010, BIT1, 0);
+
+ /*
+ * TPI_DEVICE_POWER_STATE_CTRL_REG
+ * TX_POWER_STATE_MASK = BIT1 | BIT0
+ */
+ mhl_i2c_reg_modify(TX_PAGE_TPI, 0x001E, BIT1 | BIT0, 0x00);
+ break;
+ case POWER_STATE_D3:
+ if (mhl_msm_state->cur_state != POWER_STATE_D3) {
+ /* Force HPD to 0 when not in MHL mode. */
+ mhl_i2c_reg_modify(TX_PAGE_3, 0x0020,
+ BIT5 | BIT4, BIT4);
+
+ /*
+ * Change TMDS termination to high impedance
+ * on disconnection.
+ */
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0030, 0xD0);
+ mhl_i2c_reg_modify(TX_PAGE_L1, 0x003D,
+ BIT1 | BIT0, BIT0);
+ spin_lock_irqsave(&mhl_state_lock, flags);
+ mhl_msm_state->cur_state = POWER_STATE_D3;
+ spin_unlock_irqrestore(&mhl_state_lock, flags);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void mhl_drive_hpd(uint8_t to_state)
+{
+ pr_debug("%s: To state=[0x%x]\n", __func__, to_state);
+ if (to_state == HPD_UP) {
+ /*
+ * Drive HPD to UP state
+ *
+ * The below two reg configs combined
+ * enable TMDS output.
+ */
+
+ /* Enable TMDS on TMDS_CCTRL */
+ mhl_i2c_reg_modify(TX_PAGE_L0, 0x0080, BIT4, BIT4);
+
+ /*
+ * Set HPD_OUT_OVR_EN = HPD State
+ * EDID read and Un-force HPD (from low)
+ * propogate to src let HPD float by clearing
+ * HPD OUT OVRRD EN
+ */
+ mhl_i2c_reg_modify(TX_PAGE_3, 0x0020, BIT4, 0x00);
+ } else {
+ /*
+ * Drive HPD to DOWN state
+ * Disable TMDS Output on REG_TMDS_CCTRL
+ * Enable/Disable TMDS output (MHL TMDS output only)
+ */
+ mhl_i2c_reg_modify(TX_PAGE_L0, 0x0080, BIT4, 0x00);
+ }
+ return;
+}
+
+static void mhl_msm_connection(void)
+{
+ uint8_t val;
+ unsigned long flags;
+
+ pr_err("%s: cur state = [0x%x]\n", __func__, mhl_msm_state->cur_state);
+
+ if (mhl_msm_state->cur_state == POWER_STATE_D0_MHL) {
+ /* Already in D0 - MHL power state */
+ return;
+ }
+ spin_lock_irqsave(&mhl_state_lock, flags);
+ mhl_msm_state->cur_state = POWER_STATE_D0_MHL;
+ spin_unlock_irqrestore(&mhl_state_lock, flags);
+
+ mhl_i2c_reg_write(TX_PAGE_3, 0x30, 0x10);
+
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x07, 0xF2);
+
+ /*
+ * Keep the discovery enabled. Need RGND interrupt
+ * Possibly chip disables discovery after MHL_EST??
+ * Need to re-enable here
+ */
+ val = mhl_i2c_reg_read(TX_PAGE_3, 0x10);
+ mhl_i2c_reg_write(TX_PAGE_3, 0x10, val | BIT(0));
+
+ return;
+}
+
+static void mhl_msm_disconnection(void)
+{
+ uint8_t reg;
+
+ /* Clear interrupts - REG INTR4 */
+ reg = mhl_i2c_reg_read(TX_PAGE_3, 0x0021);
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0021, reg);
+ /*
+ * MHL TX CTL1
+ * Disabling Tx termination
+ */
+ mhl_i2c_reg_write(TX_PAGE_3, 0x30, 0xD0);
+ /*
+ * MSC REQUESTOR ABORT REASON
+ * Clear CBUS_HPD status
+ */
+ mhl_i2c_reg_modify(TX_PAGE_CBUS, 0x000D, BIT6, 0x00);
+ /* Change HPD line to drive it low */
+ mhl_drive_hpd(HPD_DOWN);
+ /* switch power state to D3 */
+ switch_mode(POWER_STATE_D3);
+ return;
+}
+
+/*
+ * If hardware detected a change in impedence and raised an INTR
+ * We check the range of this impedence to infer if the connected
+ * device is MHL or USB and take appropriate actions.
+ */
+static void mhl_msm_read_rgnd_int(void)
+{
+ uint8_t rgnd_imp;
+
+ /*
+ * DISC STATUS REG 2
+ * 1:0 RGND
+ * 00 - open (USB)
+ * 01 - 2 kOHM (USB)
+ * 10 - 1 kOHM ***(MHL)**** It's range 800 - 1200 OHM from MHL spec
+ * 11 - short (USB)
+ */
+ rgnd_imp = mhl_i2c_reg_read(TX_PAGE_3, 0x001C);
+ pr_debug("Imp Range read = %02X\n", (int)rgnd_imp);
+
+
+ if (0x02 == rgnd_imp) {
+ pr_debug("MHL: MHL DEVICE!!!\n");
+ /*
+ * Handling the MHL event in driver
+ */
+ mhl_i2c_reg_modify(TX_PAGE_3, 0x0018, BIT0, BIT0);
+ } else {
+ pr_debug("MHL: NON-MHL DEVICE!!!\n");
+ mhl_i2c_reg_modify(TX_PAGE_3, 0x0018, BIT3, BIT3);
+ }
+}
+
+static void force_usb_switch_open(void)
+{
+ /*DISABLE_DISCOVERY*/
+ mhl_i2c_reg_modify(TX_PAGE_3, 0x0010, BIT0, 0);
+ /* Force USB ID switch to open*/
+ mhl_i2c_reg_modify(TX_PAGE_3, 0x0015, BIT6, BIT6);
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0012, 0x86);
+ /* Force HPD to 0 when not in Mobile HD mode. */
+ mhl_i2c_reg_modify(TX_PAGE_3, 0x0020, BIT5 | BIT4, BIT4);
+}
+
+static void release_usb_switch_open(void)
+{
+ msleep(50);
+ mhl_i2c_reg_modify(TX_PAGE_3, 0x0015, BIT6, 0x00);
+ mhl_i2c_reg_modify(TX_PAGE_3, 0x0010, BIT0, BIT0);
+}
+
+static void int_4_isr(void)
+{
+ uint8_t status;
+
+ /* INTR_STATUS4 */
+ status = mhl_i2c_reg_read(TX_PAGE_3, 0x0021);
+
+ /*
+ * When I2C is inoperational (D3) and
+ * a previous interrupt brought us here,
+ * do nothing.
+ */
+ pr_debug("MHL: MRR Interrupt status is = %02X\n", (int) status);
+ if (0xFF != status) {
+ if ((status & BIT0) && (mhl_msm_state->chip_rev_id < 1)) {
+ uint8_t tmds_cstat;
+ uint8_t mhl_fifo_status;
+
+ /* TMDS CSTAT */
+ tmds_cstat = mhl_i2c_reg_read(TX_PAGE_3, 0x0040);
+
+ pr_debug("TMDS CSTAT: 0x%02x\n", tmds_cstat);
+
+ if (tmds_cstat & 0x02) {
+ mhl_fifo_status = mhl_i2c_reg_read(TX_PAGE_3,
+ 0x0023);
+ pr_debug("MHL FIFO status: 0x%02x\n",
+ mhl_fifo_status);
+ if (mhl_fifo_status & 0x0C) {
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0023,
+ 0x0C);
+
+ pr_debug("Apply MHL FIFO Reset\n");
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0000,
+ 0x94);
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0000,
+ 0x84);
+ }
+ }
+ }
+
+ if (status & BIT1)
+ pr_err("MHL: INT4 BIT1 is set\n");
+
+ /* MHL_EST interrupt */
+ if (status & BIT2) {
+ pr_err("MHL: Calling mhl_msm_connection() from ISR\n");
+ mhl_msm_connection();
+ pr_err("MHL Connect Drv: INT4 Status = %02X\n",
+ (int) status);
+ } else if (status & BIT3) {
+ pr_err("MHL: uUSB-A type device detected.\n");
+ mhl_i2c_reg_write(TX_PAGE_3, 0x001C, 0x80);
+ switch_mode(POWER_STATE_D3);
+ }
+
+ if (status & BIT5) {
+ mhl_msm_disconnection();
+ pr_err("MHL Disconnect Drv: INT4 Status = %02X\n",
+ (int)status);
+ }
+
+ if ((mhl_msm_state->cur_state != POWER_STATE_D0_MHL) &&\
+ (status & BIT6)) {
+ /* RGND READY Intr */
+ switch_mode(POWER_STATE_D0_MHL);
+ mhl_msm_read_rgnd_int();
+ }
+
+ /* Can't succeed at these in D3 */
+ if (mhl_msm_state->cur_state != POWER_STATE_D3) {
+ /* CBUS Lockout interrupt? */
+ /*
+ * Hardware detection mechanism figures that
+ * CBUS line is latched and raises this intr
+ * where we force usb switch open and release
+ */
+ if (status & BIT4) {
+ force_usb_switch_open();
+ release_usb_switch_open();
+ }
+ }
+ }
+ pr_debug("MHL END Drv: INT4 Status = %02X\n", (int) status);
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0021, status);
+
+ return;
+}
+
+static void int_5_isr(void)
+{
+ uint8_t intr_5_stat;
+
+ /*
+ * Clear INT 5 ??
+ * Probably need to revisit this later
+ * INTR5 is related to FIFO underflow/overflow reset
+ * which is handled in 8334 by auto FIFO reset
+ */
+ intr_5_stat = mhl_i2c_reg_read(TX_PAGE_3, 0x0023);
+ mhl_i2c_reg_write(TX_PAGE_3, 0x0023, intr_5_stat);
+}
+
+
+static void int_1_isr(void)
+{
+ /* This ISR mainly handles the HPD status changes */
+ uint8_t intr_1_stat;
+ uint8_t cbus_stat;
+
+ /* INTR STATUS 1 */
+ intr_1_stat = mhl_i2c_reg_read(TX_PAGE_L0, 0x0071);
+
+ if (intr_1_stat) {
+ /* Clear interrupts */
+ mhl_i2c_reg_write(TX_PAGE_L0, 0x0071, intr_1_stat);
+ if (BIT6 & intr_1_stat) {
+ /*
+ * HPD status change event is pending
+ * Read CBUS HPD status for this info
+ */
+
+ /* MSC REQ ABRT REASON */
+ cbus_stat = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x0D);
+ if (BIT6 & cbus_stat)
+ mhl_drive_hpd(HPD_UP);
+ }
+ }
+ return;
+}
+
+/*
+ * RCP, RAP messages - mandatory for compliance
+ *
+ */
+static void mhl_cbus_isr(void)
+{
+ uint8_t regval;
+ int req_done = FALSE;
+ uint8_t sub_cmd;
+ uint8_t cmd_data;
+ int msc_msg_recved = FALSE;
+ int rc = -1;
+
+ regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x08);
+ if (regval == 0xff)
+ return;
+
+ /* clear all interrupts that were raised even if we did not process */
+ if (regval)
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x08, regval);
+
+ pr_err("%s: CBUS_INT = %02x\n", __func__, regval);
+
+ /* MSC_MSG (RCP/RAP) */
+ if (regval & BIT(3)) {
+ sub_cmd = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x18);
+ cmd_data = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x19);
+ msc_msg_recved = TRUE;
+ }
+
+ /* MSC_REQ_DONE */
+ if (regval & BIT(4))
+ req_done = TRUE;
+
+ /* Now look for interrupts on CBUS_MSC_INT2 */
+ regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x1E);
+
+ /* clear all interrupts that were raised */
+ /* even if we did not process */
+ if (regval)
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x1E, regval);
+
+ pr_err("%s: CBUS_MSC_INT2 = %02x\n", __func__, regval);
+
+ /* received SET_INT */
+ if (regval & BIT(2)) {
+ uint8_t intr;
+ intr = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xA0);
+ pr_debug("%s: MHL_INT_0 = %02x\n", __func__, intr);
+ intr = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xA1);
+ pr_debug("%s: MHL_INT_1 = %02x\n", __func__, intr);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0xA0, 0xFF);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0xA1, 0xFF);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0xA2, 0xFF);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0xA3, 0xFF);
+ }
+
+ /* received WRITE_STAT */
+ if (regval & BIT(3)) {
+ uint8_t stat;
+ stat = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xB0);
+ pr_err("%s: MHL_STATUS_0 = %02x\n", __func__, stat);
+ stat = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xB1);
+ pr_err("%s: MHL_STATUS_1 = %02x\n", __func__, stat);
+
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0xB0, 0xFF);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0xB1, 0xFF);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0xB2, 0xFF);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0xB3, 0xFF);
+ }
+
+ /* received MSC_MSG */
+ if (msc_msg_recved) {
+ /*mhl msc recv msc msg*/
+ if (rc)
+ pr_err("MHL: mhl msc recv msc msg failed(%d)!\n", rc);
+ }
+
+ return;
+}
+
+static irqreturn_t mhl_tx_isr(int irq, void *dev_id)
+{
+ /*
+ * Check discovery interrupt
+ * if not yet connected
+ */
+ pr_debug("MHL: Current POWER state is [0x%x]\n",
+ mhl_msm_state->cur_state);
+ /*
+ * Check RGND, MHL_EST, CBUS_LOCKOUT, SCDT
+ * interrupts. In D3, we get only RGND
+ */
+ int_4_isr();
+
+ pr_debug("MHL: Current POWER state is [0x%x]\n",
+ mhl_msm_state->cur_state);
+ if (mhl_msm_state->cur_state == POWER_STATE_D0_MHL) {
+ /*
+ * If int_4_isr() didn't move the tx to D3
+ * on disconnect, continue to check other
+ * interrupt sources.
+ */
+ int_5_isr();
+
+ /*
+ * Check for any peer messages for DCAP_CHG etc
+ * Dispatch to have the CBUS module working only
+ * once connected.
+ */
+ mhl_cbus_isr();
+ int_1_isr();
+ }
+ return IRQ_HANDLED;
+}
+
+static void __exit mhl_msm_exit(void)
+{
+ pr_warn("MHL: Exiting, Bye\n");
+ /*
+ * Delete driver if i2c client structure is NULL
+ */
+ i2c_del_driver(&mhl_sii_i2c_driver);
+ if (!mhl_msm_state) {
+ kfree(mhl_msm_state);
+ mhl_msm_state = NULL;
+ }
+}
+
+module_init(mhl_msm_init);
+module_exit(mhl_msm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MHL SII 8334 TX driver");
diff --git a/drivers/video/msm/mhl/mhl_8334.h b/drivers/video/msm/mhl/mhl_8334.h
new file mode 100644
index 0000000..c1d9030
--- /dev/null
+++ b/drivers/video/msm/mhl/mhl_8334.h
@@ -0,0 +1,74 @@
+/* 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 __MHL_MSM_H__
+#define __MHL_MSM_H__
+
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <mach/board.h>
+
+#include "mhl_devcap.h"
+#include "mhl_defs.h"
+
+#define GPIO_MHL_RESET 15
+#define GPIO_MHL_INT 4
+
+#define MHL_DEVICE_NAME "sii8334"
+#define MHL_DRIVER_NAME "sii8334"
+
+#define HPD_UP 1
+#define HPD_DOWN 0
+
+struct mhl_msm_state_t {
+ struct i2c_client *i2c_client;
+ struct i2c_driver *i2c_driver;
+ uint8_t cur_state;
+ uint8_t chip_rev_id;
+ struct msm_mhl_platform_data *mhl_data;
+};
+
+enum {
+ TX_PAGE_TPI = 0x00,
+ TX_PAGE_L0 = 0x01,
+ TX_PAGE_L1 = 0x02,
+ TX_PAGE_2 = 0x03,
+ TX_PAGE_3 = 0x04,
+ TX_PAGE_CBUS = 0x05,
+ TX_PAGE_DDC_EDID = 0x06,
+ TX_PAGE_DDC_SEGM = 0x07,
+};
+
+enum mhl_st_type {
+ POWER_STATE_D0_NO_MHL = 0,
+ POWER_STATE_D0_MHL = 2,
+ POWER_STATE_D3 = 3,
+};
+
+enum {
+ DEV_PAGE_TPI_0 = (0x72),
+ DEV_PAGE_TX_L0_0 = (0x72),
+ DEV_PAGE_TPI_1 = (0x76),
+ DEV_PAGE_TX_L0_1 = (0x76),
+ DEV_PAGE_TX_L1_0 = (0x7A),
+ DEV_PAGE_TX_L1_1 = (0x7E),
+ DEV_PAGE_TX_2_0 = (0x92),
+ DEV_PAGE_TX_2_1 = (0x96),
+ DEV_PAGE_TX_3_0 = (0x9A),
+ DEV_PAGE_TX_3_1 = (0x9E),
+ DEV_PAGE_CBUS = (0xC8),
+ DEV_PAGE_DDC_EDID = (0xA0),
+ DEV_PAGE_DDC_SEGM = (0x60),
+};
+
+#endif /* __MHL_MSM_H__ */
diff --git a/drivers/video/msm/mhl/mhl_defs.h b/drivers/video/msm/mhl/mhl_defs.h
new file mode 100644
index 0000000..094874e
--- /dev/null
+++ b/drivers/video/msm/mhl/mhl_defs.h
@@ -0,0 +1,222 @@
+/* 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 __MHL_SPEC_DEFS_H__
+#define __MHL_SPEC_DEFS_H__
+
+enum DevCapOffset_e {
+ DEVCAP_OFFSET_DEV_STATE = 0x00,
+ DEVCAP_OFFSET_MHL_VERSION = 0x01,
+ DEVCAP_OFFSET_DEV_CAT = 0x02,
+ DEVCAP_OFFSET_ADOPTER_ID_H = 0x03,
+ DEVCAP_OFFSET_ADOPTER_ID_L = 0x04,
+ DEVCAP_OFFSET_VID_LINK_MODE = 0x05,
+ DEVCAP_OFFSET_AUD_LINK_MODE = 0x06,
+ DEVCAP_OFFSET_VIDEO_TYPE = 0x07,
+ DEVCAP_OFFSET_LOG_DEV_MAP = 0x08,
+ DEVCAP_OFFSET_BANDWIDTH = 0x09,
+ DEVCAP_OFFSET_FEATURE_FLAG = 0x0A,
+ DEVCAP_OFFSET_DEVICE_ID_H = 0x0B,
+ DEVCAP_OFFSET_DEVICE_ID_L = 0x0C,
+ DEVCAP_OFFSET_SCRATCHPAD_SIZE = 0x0D,
+ DEVCAP_OFFSET_INT_STAT_SIZE = 0x0E,
+ DEVCAP_OFFSET_RESERVED = 0x0F,
+ /* this one must be last */
+ DEVCAP_SIZE
+};
+
+#ifndef __MHL_MSM_8334_REGS_H__
+#define __MHL_MSM_8334_REGS_H__
+
+#define BIT0 0x01
+#define BIT1 0x02
+#define BIT2 0x04
+#define BIT3 0x08
+#define BIT4 0x10
+#define BIT5 0x20
+#define BIT6 0x40
+#define BIT7 0x80
+
+#define LOW 0
+#define HIGH 1
+
+#define MAX_PAGES 8
+#endif
+
+
+/* Version that this chip supports*/
+/* bits 4..7 */
+#define MHL_VER_MAJOR (0x01 << 4)
+/* bits 0..3 */
+#define MHL_VER_MINOR 0x01
+#define MHL_VERSION (MHL_VER_MAJOR | MHL_VER_MINOR)
+
+/*Device Category*/
+#define MHL_DEV_CATEGORY_OFFSET DEVCAP_OFFSET_DEV_CAT
+#define MHL_DEV_CATEGORY_POW_BIT (BIT4)
+
+#define MHL_DEV_CAT_SOURCE 0x02
+
+/*Video Link Mode*/
+#define MHL_DEV_VID_LINK_SUPPRGB444 0x01
+#define MHL_DEV_VID_LINK_SUPPYCBCR444 0x02
+#define MHL_DEV_VID_LINK_SUPPYCBCR422 0x04
+#define MHL_DEV_VID_LINK_SUPP_PPIXEL 0x08
+#define MHL_DEV_VID_LINK_SUPP_ISLANDS 0x10
+
+/*Audio Link Mode Support*/
+#define MHL_DEV_AUD_LINK_2CH 0x01
+#define MHL_DEV_AUD_LINK_8CH 0x02
+
+
+/*Feature Flag in the devcap*/
+#define MHL_DEV_FEATURE_FLAG_OFFSET DEVCAP_OFFSET_FEATURE_FLAG
+/* Dongles have freedom to not support RCP */
+#define MHL_FEATURE_RCP_SUPPORT BIT0
+/* Dongles have freedom to not support RAP */
+#define MHL_FEATURE_RAP_SUPPORT BIT1
+/* Dongles have freedom to not support SCRATCHPAD */
+#define MHL_FEATURE_SP_SUPPORT BIT2
+
+/*Logical Dev Map*/
+#define MHL_DEV_LD_DISPLAY (0x01 << 0)
+#define MHL_DEV_LD_VIDEO (0x01 << 1)
+#define MHL_DEV_LD_AUDIO (0x01 << 2)
+#define MHL_DEV_LD_MEDIA (0x01 << 3)
+#define MHL_DEV_LD_TUNER (0x01 << 4)
+#define MHL_DEV_LD_RECORD (0x01 << 5)
+#define MHL_DEV_LD_SPEAKER (0x01 << 6)
+#define MHL_DEV_LD_GUI (0x01 << 7)
+
+/*Bandwidth*/
+/* 225 MHz */
+#define MHL_BANDWIDTH_LIMIT 22
+
+
+#define MHL_STATUS_REG_CONNECTED_RDY 0x30
+#define MHL_STATUS_REG_LINK_MODE 0x31
+
+#define MHL_STATUS_DCAP_RDY BIT0
+
+#define MHL_STATUS_CLK_MODE_MASK 0x07
+#define MHL_STATUS_CLK_MODE_PACKED_PIXEL 0x02
+#define MHL_STATUS_CLK_MODE_NORMAL 0x03
+#define MHL_STATUS_PATH_EN_MASK 0x08
+#define MHL_STATUS_PATH_ENABLED 0x08
+#define MHL_STATUS_PATH_DISABLED 0x00
+#define MHL_STATUS_MUTED_MASK 0x10
+
+#define MHL_RCHANGE_INT 0x20
+#define MHL_DCHANGE_INT 0x21
+
+#define MHL_INT_DCAP_CHG BIT0
+#define MHL_INT_DSCR_CHG BIT1
+#define MHL_INT_REQ_WRT BIT2
+#define MHL_INT_GRT_WRT BIT3
+
+/* On INTR_1 the EDID_CHG is located at BIT 0*/
+#define MHL_INT_EDID_CHG BIT1
+
+/* This contains one nibble each - max offset */
+#define MHL_INT_AND_STATUS_SIZE 0x33
+#define MHL_SCRATCHPAD_SIZE 16
+/* manually define highest number */
+#define MHL_MAX_BUFFER_SIZE MHL_SCRATCHPAD_SIZE
+
+
+
+enum {
+ /* RCP sub-command */
+ MHL_MSC_MSG_RCP = 0x10,
+ /* RCP Acknowledge sub-command */
+ MHL_MSC_MSG_RCPK = 0x11,
+ /* RCP Error sub-command */
+ MHL_MSC_MSG_RCPE = 0x12,
+ /* Mode Change Warning sub-command */
+ MHL_MSC_MSG_RAP = 0x20,
+ /* MCW Acknowledge sub-command */
+ MHL_MSC_MSG_RAPK = 0x21,
+};
+
+#define RCPE_NO_ERROR 0x00
+#define RCPE_INEEFECTIVE_KEY_CODE 0x01
+#define RCPE_BUSY 0x02
+/* MHL spec related defines*/
+enum {
+ /* Command or Data byte acknowledge */
+ MHL_ACK = 0x33,
+ /* Command or Data byte not acknowledge */
+ MHL_NACK = 0x34,
+ /* Transaction abort */
+ MHL_ABORT = 0x35,
+ /* 0xE0 - Write one status register strip top bit */
+ MHL_WRITE_STAT = 0x60 | 0x80,
+ /* Write one interrupt register */
+ MHL_SET_INT = 0x60,
+ /* Read one register */
+ MHL_READ_DEVCAP = 0x61,
+ /* Read CBUS revision level from follower */
+ MHL_GET_STATE = 0x62,
+ /* Read vendor ID value from follower. */
+ MHL_GET_VENDOR_ID = 0x63,
+ /* Set Hot Plug Detect in follower */
+ MHL_SET_HPD = 0x64,
+ /* Clear Hot Plug Detect in follower */
+ MHL_CLR_HPD = 0x65,
+ /* Set Capture ID for downstream device. */
+ MHL_SET_CAP_ID = 0x66,
+ /* Get Capture ID from downstream device. */
+ MHL_GET_CAP_ID = 0x67,
+ /* VS command to send RCP sub-commands */
+ MHL_MSC_MSG = 0x68,
+ /* Get Vendor-Specific command error code. */
+ MHL_GET_SC1_ERRORCODE = 0x69,
+ /* Get DDC channel command error code. */
+ MHL_GET_DDC_ERRORCODE = 0x6A,
+ /* Get MSC command error code. */
+ MHL_GET_MSC_ERRORCODE = 0x6B,
+ /* Write 1-16 bytes to responder's scratchpad. */
+ MHL_WRITE_BURST = 0x6C,
+ /* Get channel 3 command error code. */
+ MHL_GET_SC3_ERRORCODE = 0x6D,
+};
+
+/* Turn content streaming ON. */
+#define MHL_RAP_CONTENT_ON 0x10
+/* Turn content streaming OFF. */
+#define MHL_RAP_CONTENT_OFF 0x11
+
+/*
+ *
+ * MHL Timings applicable to this driver.
+ *
+ */
+/* 100 - 1000 milliseconds. Per MHL 1.0 Specs */
+#define T_SRC_VBUS_CBUS_TO_STABLE (200)
+/* 20 milliseconds. Per MHL 1.0 Specs */
+#define T_SRC_WAKE_PULSE_WIDTH_1 (20)
+/* 60 milliseconds. Per MHL 1.0 Specs */
+#define T_SRC_WAKE_PULSE_WIDTH_2 (60)
+
+/* 100 - 1000 milliseconds. Per MHL 1.0 Specs */
+#define T_SRC_WAKE_TO_DISCOVER (500)
+
+#define T_SRC_VBUS_CBUS_T0_STABLE (500)
+
+/* Allow RSEN to stay low this much before reacting.*/
+#define T_SRC_RSEN_DEGLITCH (100)
+
+/* Wait this much after connection before reacting to RSEN (300-500ms)*/
+/* Per specs between 300 to 500 ms*/
+#define T_SRC_RXSENSE_CHK (400)
+
+#endif /* __MHL_SPEC_DEFS_H__ */
diff --git a/drivers/video/msm/mhl/mhl_devcap.h b/drivers/video/msm/mhl/mhl_devcap.h
new file mode 100644
index 0000000..6d01daf
--- /dev/null
+++ b/drivers/video/msm/mhl/mhl_devcap.h
@@ -0,0 +1,45 @@
+/* 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 __MHL_DEVCAP_H__
+#define __MHL_DEVCAP_H__
+
+#define SILICON_IMAGE_ADOPTER_ID 322
+#define TRANSCODER_DEVICE_ID 0x8334
+
+#define MHL_DEV_LD_AUDIO (0x01 << 2)
+#define MHL_DEV_LD_VIDEO (0x01 << 1)
+#define MHL_DEV_LD_MEDIA (0x01 << 3)
+#define MHL_DEV_LD_GUI (0x01 << 7)
+#define MHL_LOGICAL_DEVICE_MAP (MHL_DEV_LD_AUDIO |\
+ MHL_DEV_LD_VIDEO | MHL_DEV_LD_MEDIA | MHL_DEV_LD_GUI)
+
+#define DEVCAP_VAL_DEV_STATE 0
+#define DEVCAP_VAL_MHL_VERSION MHL_VERSION
+#define DEVCAP_VAL_DEV_CAT (MHL_DEV_CAT_SOURCE |\
+ MHL_DEV_CATEGORY_POW_BIT)
+#define DEVCAP_VAL_ADOPTER_ID_H (uint8_t)(SILICON_IMAGE_ADOPTER_ID >> 8)
+#define DEVCAP_VAL_ADOPTER_ID_L (uint8_t)(SILICON_IMAGE_ADOPTER_ID & 0xFF)
+#define DEVCAP_VAL_VID_LINK_MODE MHL_DEV_VID_LINK_SUPPRGB444
+#define DEVCAP_VAL_AUD_LINK_MODE MHL_DEV_AUD_LINK_2CH
+#define DEVCAP_VAL_VIDEO_TYPE 0
+#define DEVCAP_VAL_LOG_DEV_MAP MHL_LOGICAL_DEVICE_MAP
+#define DEVCAP_VAL_BANDWIDTH 0
+#define DEVCAP_VAL_FEATURE_FLAG (MHL_FEATURE_RCP_SUPPORT |\
+ MHL_FEATURE_RAP_SUPPORT | MHL_FEATURE_SP_SUPPORT)
+#define DEVCAP_VAL_DEVICE_ID_H (uint8_t)(TRANSCODER_DEVICE_ID >> 8)
+#define DEVCAP_VAL_DEVICE_ID_L (uint8_t)(TRANSCODER_DEVICE_ID & 0xFF)
+#define DEVCAP_VAL_SCRATCHPAD_SIZE MHL_SCRATCHPAD_SIZE
+#define DEVCAP_VAL_INT_STAT_SIZE MHL_INT_AND_STATUS_SIZE
+#define DEVCAP_VAL_RESERVED 0
+
+#endif /* __MHL_DEVCAP_H__ */
diff --git a/drivers/video/msm/mhl/mhl_i2c_utils.c b/drivers/video/msm/mhl/mhl_i2c_utils.c
new file mode 100644
index 0000000..596af2e
--- /dev/null
+++ b/drivers/video/msm/mhl/mhl_i2c_utils.c
@@ -0,0 +1,107 @@
+/* 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/i2c.h>
+
+#include "mhl_i2c_utils.h"
+#include "mhl_8334.h"
+
+#define DEBUG
+
+uint8_t slave_addrs[MAX_PAGES] = {
+ DEV_PAGE_TPI_0 ,
+ DEV_PAGE_TX_L0_0 ,
+ DEV_PAGE_TX_L1_0 ,
+ DEV_PAGE_TX_2_0 ,
+ DEV_PAGE_TX_3_0 ,
+ DEV_PAGE_CBUS ,
+ DEV_PAGE_DDC_EDID ,
+ DEV_PAGE_DDC_SEGM ,
+};
+
+int mhl_i2c_reg_read(uint8_t slave_addr_index, uint8_t reg_offset)
+{
+ struct i2c_msg msgs[2];
+ uint8_t buffer = 0;
+ int ret = -1;
+
+ pr_debug("MRR: Reading from slave_addr_index=[%x] and offset=[%x]\n",
+ slave_addr_index, reg_offset);
+ pr_debug("MRR: Addr slave_addr_index=[%x]\n",
+ slave_addrs[slave_addr_index]);
+
+ /* Slave addr */
+ msgs[0].addr = slave_addrs[slave_addr_index] >> 1;
+ msgs[1].addr = slave_addrs[slave_addr_index] >> 1;
+
+ /* Write Command */
+ msgs[0].flags = 0;
+ msgs[1].flags = I2C_M_RD;
+
+ /* Register offset for the next transaction */
+ msgs[0].buf = ®_offset;
+ msgs[1].buf = &buffer;
+
+ /* Offset is 1 Byte long */
+ msgs[0].len = 1;
+ msgs[1].len = 1;
+
+ ret = i2c_transfer(mhl_msm_state->i2c_client->adapter, msgs, 2);
+ if (ret < 1) {
+ pr_err("I2C READ FAILED=[%d]\n", ret);
+ return -EACCES;
+ }
+ pr_err("Buffer is [%x]\n", buffer);
+ return buffer;
+}
+
+
+int mhl_i2c_reg_write(uint8_t slave_addr_index, uint8_t reg_offset,
+ uint8_t value)
+{
+ return mhl_i2c_reg_write_cmds(slave_addr_index, reg_offset, &value, 1);
+}
+
+int mhl_i2c_reg_write_cmds(uint8_t slave_addr_index, uint8_t reg_offset,
+ uint8_t *value, uint16_t count)
+{
+ struct i2c_msg msgs[1];
+ uint8_t data[2];
+ int status = -EACCES;
+
+ msgs[0].addr = slave_addrs[slave_addr_index] >> 1;
+ msgs[0].flags = 0;
+ msgs[0].len = 2;
+ msgs[0].buf = data;
+ data[0] = reg_offset;
+ data[1] = *value;
+
+ status = i2c_transfer(mhl_msm_state->i2c_client->adapter, msgs, 1);
+ if (status < 1) {
+ pr_err("I2C WRITE FAILED=[%d]\n", status);
+ return -EACCES;
+ }
+
+ return status;
+}
+
+void mhl_i2c_reg_modify(uint8_t slave_addr_index, uint8_t reg_offset,
+ uint8_t mask, uint8_t val)
+{
+ uint8_t temp;
+
+ temp = mhl_i2c_reg_read(slave_addr_index, reg_offset);
+ temp &= (~mask);
+ temp |= (mask & val);
+ mhl_i2c_reg_write(slave_addr_index, reg_offset, temp);
+}
+
diff --git a/drivers/video/msm/mhl/mhl_i2c_utils.h b/drivers/video/msm/mhl/mhl_i2c_utils.h
new file mode 100644
index 0000000..76498d4
--- /dev/null
+++ b/drivers/video/msm/mhl/mhl_i2c_utils.h
@@ -0,0 +1,39 @@
+/* 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 __MHL_I2C_UTILS_H__
+#define __MHL_I2C_UTILS_H__
+
+#include <linux/i2c.h>
+#include <linux/types.h>
+
+#include "mhl_defs.h"
+
+/*
+ * I2C command to the adapter to append
+ * the buffer from next msg to this one.
+ */
+#define I2C_M_APPND_NXT_WR 0x0002
+
+extern uint8_t slave_addrs[MAX_PAGES];
+extern struct mhl_msm_state_t *mhl_msm_state;
+
+int mhl_i2c_reg_read(uint8_t slave_addr_index, uint8_t reg_offset);
+int mhl_i2c_reg_write(uint8_t slave_addr_index, uint8_t reg_offset,
+ uint8_t value);
+int mhl_i2c_reg_write_cmds(uint8_t slave_addr_index, uint8_t reg_offset,
+ uint8_t *value, uint16_t count);
+void mhl_i2c_reg_modify(uint8_t slave_addr_index, uint8_t reg_offset,
+ uint8_t mask, uint8_t val);
+
+#endif /* __MHL_I2C_UTILS_H__ */
diff --git a/drivers/video/msm/mhl_api.h b/drivers/video/msm/mhl_api.h
index 627f802..a4364ea 100644
--- a/drivers/video/msm/mhl_api.h
+++ b/drivers/video/msm/mhl_api.h
@@ -14,7 +14,7 @@
#ifndef __MHL_API_H__
#define __MHL_API_H__
-#ifdef CONFIG_FB_MSM_HDMI_MHL
+#ifdef CONFIG_FB_MSM_HDMI_MHL_8334
bool mhl_is_connected(void);
#else
static bool mhl_is_connected(void)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
index b720800..62f0976 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -1000,7 +1000,8 @@
(decoder->frame_size.scan_lines ==
decoder->client_frame_size.scan_lines) &&
(decoder->frame_size.stride ==
- decoder->client_frame_size.stride))
+ decoder->client_frame_size.stride) &&
+ decoder->progressive_only)
need_reconfig = false;
}
return need_reconfig;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
index 86e9ff6..0d5ba9c 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
@@ -342,6 +342,7 @@
static u32 vcd_flush_in_eos(struct vcd_clnt_ctxt *cctxt,
u32 mode)
{
+ u32 rc = VCD_S_SUCCESS;
VCD_MSG_LOW("vcd_flush_in_eos:");
if (mode > VCD_FLUSH_ALL || !mode) {
@@ -351,10 +352,18 @@
}
VCD_MSG_MED("Flush mode requested %d", mode);
+ if (!(cctxt->status.frame_submitted) &&
+ (!cctxt->decoding)) {
+ rc = vcd_flush_buffers(cctxt, mode);
+ if (!VCD_FAILED(rc)) {
+ VCD_MSG_HIGH("All buffers are flushed");
+ cctxt->status.mask |= (mode & VCD_FLUSH_ALL);
+ vcd_send_flush_done(cctxt, VCD_S_SUCCESS);
+ }
+ } else
+ cctxt->status.mask |= (mode & VCD_FLUSH_ALL);
- cctxt->status.mask |= (mode & VCD_FLUSH_ALL);
-
- return VCD_S_SUCCESS;
+ return rc;
}
static u32 vcd_flush_in_invalid(struct vcd_clnt_ctxt *cctxt,
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index e7cc68e..1dae562 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1031,6 +1031,55 @@
* %NL80211_CMD_SET_BEACON to provide extra IEs (e.g., WPS/P2P IE) into
* (Re)Association Response frames when the driver (or firmware) replies to
* (Re)Association Request frames.
+ * @NL80211_ATTR_STA_WME: Nested attribute containing the wme configuration
+ * of the station, see &enum nl80211_sta_wme_attr.
+ * @NL80211_ATTR_SUPPORT_AP_UAPSD: the device supports uapsd when working
+ * as AP.
+ *
+ * @NL80211_ATTR_ROAM_SUPPORT: Indicates whether the firmware is capable of
+ * roaming to another AP in the same ESS if the signal lever is low.
+ *
+ * @NL80211_ATTR_PMKSA_CANDIDATE: Nested attribute containing the PMKSA caching
+ * candidate information, see &enum nl80211_pmksa_candidate_attr.
+ *
+ * @NL80211_ATTR_TX_NO_CCK_RATE: Indicates whether to use CCK rate or not
+ * for management frames transmission. In order to avoid p2p probe/action
+ * frames are being transmitted at CCK rate in 2GHz band, the user space
+ * applications use this attribute.
+ * This attribute is used with %NL80211_CMD_TRIGGER_SCAN and
+ * %NL80211_CMD_FRAME commands.
+ *
+ * @NL80211_ATTR_TDLS_ACTION: Low level TDLS action code (e.g. link setup
+ * request, link setup confirm, link teardown, etc.). Values are
+ * described in the TDLS (802.11z) specification.
+ * @NL80211_ATTR_TDLS_DIALOG_TOKEN: Non-zero token for uniquely identifying a
+ * TDLS conversation between two devices.
+ * @NL80211_ATTR_TDLS_OPERATION: High level TDLS operation; see
+ * &enum nl80211_tdls_operation, represented as a u8.
+ * @NL80211_ATTR_TDLS_SUPPORT: A flag indicating the device can operate
+ * as a TDLS peer sta.
+ * @NL80211_ATTR_TDLS_EXTERNAL_SETUP: The TDLS discovery/setup and teardown
+ * procedures should be performed by sending TDLS packets via
+ * %NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be
+ * used for asking the driver to perform a TDLS operation.
+ *
+ * @NL80211_ATTR_DEVICE_AP_SME: This u32 attribute may be listed for devices
+ * that have AP support to indicate that they have the AP SME integrated
+ * with support for the features listed in this attribute, see
+ * &enum nl80211_ap_sme_features.
+ *
+ * @NL80211_ATTR_DONT_WAIT_FOR_ACK: Used with %NL80211_CMD_FRAME, this tells
+ * the driver to not wait for an acknowledgement. Note that due to this,
+ * it will also not give a status callback nor return a cookie. This is
+ * mostly useful for probe responses to save airtime.
+ *
+ * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from
+ * &enum nl80211_feature_flags and is advertised in wiphy information.
+ * @NL80211_ATTR_PROBE_RESP_OFFLOAD: Indicates that the HW responds to probe
+ *
+ * requests while operating in AP-mode.
+ * This attribute holds a bitmap of the supported protocols for
+ * offloading (see &enum nl80211_probe_resp_offload_support_attr).
*
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -1254,6 +1303,19 @@
NL80211_ATTR_TX_NO_CCK_RATE,
+ NL80211_ATTR_TDLS_ACTION,
+ NL80211_ATTR_TDLS_DIALOG_TOKEN,
+ NL80211_ATTR_TDLS_OPERATION,
+ NL80211_ATTR_TDLS_SUPPORT,
+ NL80211_ATTR_TDLS_EXTERNAL_SETUP,
+ NL80211_ATTR_DEVICE_AP_SME,
+
+ NL80211_ATTR_DONT_WAIT_FOR_ACK,
+
+ NL80211_ATTR_FEATURE_FLAGS,
+
+ NL80211_ATTR_PROBE_RESP_OFFLOAD,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -2436,4 +2498,35 @@
NL80211_HIDDEN_SSID_ZERO_CONTENTS
};
+/*
+ * enum nl80211_ap_sme_features - device-integrated AP features
+ * Reserved for future use, no bits are defined in
+ * NL80211_ATTR_DEVICE_AP_SME yet.
+enum nl80211_ap_sme_features {
+};
+ */
+
+/**
+ * enum nl80211_probe_resp_offload_support_attr - optional supported
+ * protocols for probe-response offloading by the driver/FW.
+ * To be used with the %NL80211_ATTR_PROBE_RESP_OFFLOAD attribute.
+ * Each enum value represents a bit in the bitmap of supported
+ * protocols. Typically a subset of probe-requests belonging to a
+ * supported protocol will be excluded from offload and uploaded
+ * to the host.
+ *
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS: Support for WPS ver. 1
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2: Support for WPS ver. 2
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P: Support for P2P
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U: Support for 802.11u
+ */
+
+enum nl80211_probe_resp_offload_support_attr {
+ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS = 1<<0,
+ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 = 1<<1,
+ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P = 1<<2,
+ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U = 1<<3,
+};
+
+
#endif /* __LINUX_NL80211_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 4898ea2..53c7196 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1584,6 +1584,21 @@
* @WIPHY_FLAG_MESH_AUTH: The device supports mesh authentication by routing
* auth frames to userspace. See @NL80211_MESH_SETUP_USERSPACE_AUTH.
* @WIPHY_FLAG_SUPPORTS_SCHED_SCAN: The device supports scheduled scans.
+ * @WIPHY_FLAG_SUPPORTS_FW_ROAM: The device supports roaming feature in the
+ * firmware.
+ * @WIPHY_FLAG_AP_UAPSD: The device supports uapsd on AP.
+ * @WIPHY_FLAG_SUPPORTS_TDLS: The device supports TDLS (802.11z) operation.
+ * @WIPHY_FLAG_TDLS_EXTERNAL_SETUP: The device does not handle TDLS (802.11z)
+ * link setup/discovery operations internally. Setup, discovery and
+ * teardown packets should be sent through the @NL80211_CMD_TDLS_MGMT
+ * command. When this flag is not set, @NL80211_CMD_TDLS_OPER should be
+ * used for asking the driver/firmware to perform a TDLS operation.
+ * @WIPHY_FLAG_HAVE_AP_SME: device integrates AP SME
+ * @WIPHY_FLAG_REPORTS_OBSS: the device will report beacons from other BSSes
+ * when there are virtual interfaces in AP mode by calling
+ * cfg80211_report_obss_beacon().
+ * @WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD: When operating as an AP, the device
+ * responds to probe-requests in hardware.
*/
enum wiphy_flags {
WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
@@ -1598,6 +1613,13 @@
WIPHY_FLAG_MESH_AUTH = BIT(10),
WIPHY_FLAG_SUPPORTS_SCHED_SCAN = BIT(11),
WIPHY_FLAG_ENFORCE_COMBINATIONS = BIT(12),
+ WIPHY_FLAG_SUPPORTS_FW_ROAM = BIT(13),
+ WIPHY_FLAG_AP_UAPSD = BIT(14),
+ WIPHY_FLAG_SUPPORTS_TDLS = BIT(15),
+ WIPHY_FLAG_TDLS_EXTERNAL_SETUP = BIT(16),
+ WIPHY_FLAG_HAVE_AP_SME = BIT(17),
+ WIPHY_FLAG_REPORTS_OBSS = BIT(18),
+ WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD = BIT(19),
};
/**
@@ -1788,6 +1810,7 @@
* may request, if implemented.
*
* @wowlan: WoWLAN support information
+ * @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features.
*/
struct wiphy {
/* assign these fields before you register the wiphy */
@@ -1811,6 +1834,8 @@
u32 flags;
+ u32 ap_sme_capa;
+
enum cfg80211_signal_type signal_type;
int bss_priv_size;
@@ -1838,6 +1863,13 @@
u32 available_antennas_tx;
u32 available_antennas_rx;
+ /*
+ * Bitmap of supported protocols for probe response offloading
+ * see &enum nl80211_probe_resp_offload_support_attr. Only valid
+ * when the wiphy flag @WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD is set.
+ */
+ u32 probe_resp_offload;
+
/* If multiple wiphys are registered and you're handed e.g.
* a regular netdev with assigned ieee80211_ptr, you won't
* know whether it points to a wiphy your driver has registered
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index f71d743..782ee8d 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -992,6 +992,7 @@
struct asm_qcelp13_read_cfg qcelp13;
struct asm_sbc_read_cfg sbc;
struct asm_amrwb_read_cfg amrwb;
+ struct asm_multi_channel_pcm_fmt_blk mpcm;
} __attribute__((packed)) cfg;
};
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index c3d4bd5..aec4171 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -238,6 +238,9 @@
int q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
uint32_t rate, uint32_t channels);
+int q6asm_enc_cfg_blk_multi_ch_pcm(struct audio_client *ac,
+ uint32_t rate, uint32_t channels);
+
int q6asm_enable_sbrps(struct audio_client *ac,
uint32_t sbr_ps);
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 8d52423..f51b006 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -815,6 +815,7 @@
struct mutex mutex;
struct mutex dapm_mutex;
struct mutex dsp_mutex;
+ spinlock_t dsp_spinlock;
bool instantiated;
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 880dbe2..e921d00 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -488,6 +488,10 @@
int i;
u16 ifmodes = wiphy->interface_modes;
+ if (WARN_ON(wiphy->ap_sme_capa &&
+ !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME)))
+ return -EINVAL;
+
if (WARN_ON(wiphy->addresses && !wiphy->n_addresses))
return -EINVAL;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index bf6915b..e6457ff 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -718,6 +718,10 @@
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
dev->wiphy.available_antennas_rx);
+ if (dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD)
+ NLA_PUT_U32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
+ dev->wiphy.probe_resp_offload);
+
if ((dev->wiphy.available_antennas_tx ||
dev->wiphy.available_antennas_rx) && dev->ops->get_antenna) {
u32 tx_ant = 0, rx_ant = 0;
@@ -954,6 +958,10 @@
if (nl80211_put_iface_combinations(&dev->wiphy, msg))
goto nla_put_failure;
+ if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME)
+ NLA_PUT_U32(msg, NL80211_ATTR_DEVICE_AP_SME,
+ dev->wiphy.ap_sme_capa);
+
return genlmsg_end(msg, hdr);
nla_put_failure:
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 14d9adf..4c9cef9 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -62,7 +62,7 @@
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 4,
.rate_min = 8000,
.rate_max = 48000,
},
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index b0cfd34..a53dd44 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -1007,7 +1007,7 @@
SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 4,
.rate_min = 8000,
.rate_max = 48000,
},
diff --git a/sound/soc/msm/msm-pcm-q6.c b/sound/soc/msm/msm-pcm-q6.c
index dd194d6..4686386 100644
--- a/sound/soc/msm/msm-pcm-q6.c
+++ b/sound/soc/msm/msm-pcm-q6.c
@@ -55,7 +55,7 @@
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 4,
.buffer_bytes_max = CAPTURE_NUM_PERIODS * CAPTURE_PERIOD_SIZE,
.period_bytes_min = CAPTURE_PERIOD_SIZE,
.period_bytes_max = CAPTURE_PERIOD_SIZE,
@@ -248,8 +248,14 @@
pr_debug("Samp_rate = %d\n", prtd->samp_rate);
pr_debug("Channel = %d\n", prtd->channel_mode);
- ret = q6asm_enc_cfg_blk_pcm(prtd->audio_client, prtd->samp_rate,
- prtd->channel_mode);
+ if (prtd->channel_mode > 2) {
+ ret = q6asm_enc_cfg_blk_multi_ch_pcm(prtd->audio_client,
+ prtd->samp_rate, prtd->channel_mode);
+ } else {
+ ret = q6asm_enc_cfg_blk_pcm(prtd->audio_client,
+ prtd->samp_rate, prtd->channel_mode);
+ }
+
if (ret < 0)
pr_debug("%s: cmd cfg pcm was block failed", __func__);
@@ -331,13 +337,6 @@
/* Capture path */
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
runtime->hw = msm_pcm_hardware_capture;
- ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM);
- if (ret < 0) {
- pr_err("%s: pcm in open failed\n", __func__);
- q6asm_audio_client_free(prtd->audio_client);
- kfree(prtd);
- return -ENOMEM;
- }
}
pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
@@ -622,12 +621,28 @@
struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
struct audio_buffer *buf;
int dir, ret;
+ int format = FORMAT_LINEAR_PCM;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dir = IN;
else
dir = OUT;
+ /*capture path*/
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (params_channels(params) > 2)
+ format = FORMAT_MULTI_CHANNEL_LINEAR_PCM;
+ pr_debug("%s format = :0x%x\n", __func__, format);
+
+ ret = q6asm_open_read(prtd->audio_client, format);
+ if (ret < 0) {
+ pr_err("%s: q6asm_open_read failed\n", __func__);
+ q6asm_audio_client_free(prtd->audio_client);
+ kfree(prtd);
+ return -ENOMEM;
+ }
+ }
+
ret = q6asm_audio_client_buf_alloc_contiguous(dir,
prtd->audio_client,
runtime->hw.period_bytes_min,
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index c58bdf5..18f95f6 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -1842,8 +1842,9 @@
if (fe_dai_map[i][session_type] != INVALID_SESSION) {
channels = bedai->channel;
- if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
- (channels > 2))
+ if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+ substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ && (channels > 2))
adm_multi_ch_copp_open(bedai->port_id,
path_type,
bedai->sample_rate,
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index e254cce..9dad1bb 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -520,9 +520,6 @@
}
codec_clk = clk_get(cpu_dai->dev, "osr_clk");
- sitar_hs_detect(codec, &hs_jack, &button_jack, sitar_mbhc_cal,
- SITAR_MICBIAS2, msm8930_enable_codec_ext_clk, 0,
- SITAR_EXT_CLK_RATE);
return 0;
}
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index bc5c007..3745b17 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -489,6 +489,11 @@
} else if (channel_mode == 2) {
open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
+ } else if (channel_mode == 4) {
+ open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
+ open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
+ open.dev_channel_mapping[2] = PCM_CHANNEL_RB;
+ open.dev_channel_mapping[3] = PCM_CHANNEL_LB;
} else if (channel_mode == 6) {
open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index c7ebd2c..f3a2383 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -1228,6 +1228,10 @@
open.uMode = STREAM_PRIORITY_HIGH;
open.format = LINEAR_PCM;
break;
+ case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
+ open.uMode = STREAM_PRIORITY_HIGH;
+ open.format = MULTI_CHANNEL_PCM;
+ break;
case FORMAT_MPEG4_AAC:
open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
open.format = MPEG4_AAC;
@@ -1664,6 +1668,56 @@
return -EINVAL;
}
+int q6asm_enc_cfg_blk_multi_ch_pcm(struct audio_client *ac,
+ uint32_t rate, uint32_t channels)
+{
+ struct asm_stream_cmd_encdec_cfg_blk enc_cfg;
+
+ int rc = 0;
+
+ pr_debug("%s: Session %d, rate = %d, channels = %d\n", __func__,
+ ac->session, rate, channels);
+
+ q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+ enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ enc_cfg.param_id = ASM_ENCDEC_CFG_BLK_ID;
+ enc_cfg.param_size = sizeof(struct asm_encode_cfg_blk);
+ enc_cfg.enc_blk.frames_per_buf = 1;
+ enc_cfg.enc_blk.format_id = MULTI_CHANNEL_PCM;
+ enc_cfg.enc_blk.cfg_size =
+ sizeof(struct asm_multi_channel_pcm_fmt_blk);
+ enc_cfg.enc_blk.cfg.mpcm.num_channels = channels;
+ enc_cfg.enc_blk.cfg.mpcm.bits_per_sample = 16;
+ enc_cfg.enc_blk.cfg.mpcm.sample_rate = rate;
+ enc_cfg.enc_blk.cfg.mpcm.is_signed = 1;
+ enc_cfg.enc_blk.cfg.mpcm.is_interleaved = 1;
+ enc_cfg.enc_blk.cfg.mpcm.channel_mapping[0] = PCM_CHANNEL_FL;
+ enc_cfg.enc_blk.cfg.mpcm.channel_mapping[1] = PCM_CHANNEL_FR;
+ enc_cfg.enc_blk.cfg.mpcm.channel_mapping[2] = PCM_CHANNEL_RB;
+ enc_cfg.enc_blk.cfg.mpcm.channel_mapping[3] = PCM_CHANNEL_LB;
+ enc_cfg.enc_blk.cfg.mpcm.channel_mapping[4] = 0;
+ enc_cfg.enc_blk.cfg.mpcm.channel_mapping[5] = 0;
+ enc_cfg.enc_blk.cfg.mpcm.channel_mapping[6] = 0;
+ enc_cfg.enc_blk.cfg.mpcm.channel_mapping[7] = 0;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+ if (rc < 0) {
+ pr_err("Comamnd open failed\n");
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("timeout opcode[0x%x] ", enc_cfg.hdr.opcode);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
int q6asm_enable_sbrps(struct audio_client *ac,
uint32_t sbr_ps_enable)
{
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 0068c2a..f47b0d3 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3812,6 +3812,7 @@
mutex_init(&card->mutex);
mutex_init(&card->dapm_mutex);
mutex_init(&card->dsp_mutex);
+ spin_lock_init(&card->dsp_spinlock);
mutex_lock(&client_mutex);
list_add(&card->list, &card_list);
diff --git a/sound/soc/soc-dsp.c b/sound/soc/soc-dsp.c
index 6d4f178..1fb5585 100644
--- a/sound/soc/soc-dsp.c
+++ b/sound/soc/soc-dsp.c
@@ -635,10 +635,15 @@
{
struct snd_soc_dsp_params *dsp_params;
int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&fe->card->dsp_spinlock, flags);
if ((cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) ||
- (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH))
+ (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH)) {
+ spin_unlock_irqrestore(&fe->card->dsp_spinlock, flags);
return ret;
+ }
list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
@@ -687,10 +692,14 @@
}
break;
}
- if (ret < 0)
+
+ if (ret < 0) {
+ spin_unlock_irqrestore(&fe->card->dsp_spinlock, flags);
return ret;
+ }
}
+ spin_unlock_irqrestore(&fe->card->dsp_spinlock, flags);
return ret;
}
EXPORT_SYMBOL_GPL(soc_dsp_be_dai_trigger);