Merge "msm: pm: Adjust for events with hard wakeups"
diff --git a/arch/arm/boot/dts/msm8974_pm.dtsi b/arch/arm/boot/dts/msm8974_pm.dtsi
index f3efbb8..8e3f4b8 100644
--- a/arch/arm/boot/dts/msm8974_pm.dtsi
+++ b/arch/arm/boot/dts/msm8974_pm.dtsi
@@ -309,8 +309,9 @@
qcom,ipc-bit-offset = <1>;
qcom,gic-parent = <&intc>;
- qcom,gic-map = <47 180>, /* usb2_hsic_async_wakeup_irq */
+ qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
<53 104>, /* mdss_irq */
+ <62 222>, /* ee0_krait_hlos_spmi_periph_irq */
<0xff 57>, /* mss_to_apps_irq(0) */
<0xff 58>, /* mss_to_apps_irq(1) */
<0xff 59>, /* mss_to_apps_irq(2) */
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index b08869a..db184cd 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -69,6 +69,7 @@
CONFIG_MSM_DSPS=y
CONFIG_MSM_IPC_ROUTER=y
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_AVS_HW=y
# CONFIG_MSM_HW3D is not set
CONFIG_MSM_PIL_QDSP6V4=y
CONFIG_MSM_PIL_RIVA=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 26e7f32..5415425 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -68,6 +68,7 @@
CONFIG_MSM_DSPS=y
CONFIG_MSM_IPC_ROUTER=y
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_AVS_HW=y
# CONFIG_MSM_HW3D is not set
CONFIG_MSM_PIL_QDSP6V4=y
CONFIG_MSM_PIL_RIVA=y
diff --git a/arch/arm/mach-msm/acpuclock-7627.c b/arch/arm/mach-msm/acpuclock-7627.c
index 7be3667..1a2ae48 100644
--- a/arch/arm/mach-msm/acpuclock-7627.c
+++ b/arch/arm/mach-msm/acpuclock-7627.c
@@ -739,7 +739,8 @@
}
}
- if (!(plls_enabled & (1 << tgt_s->pll))) {
+ if ((tgt_s->pll != ACPU_PLL_TCXO) &&
+ !(plls_enabled & (1 << tgt_s->pll))) {
rc = clk_enable(pll_clk[tgt_s->pll].clk);
if (rc < 0) {
pr_err("PLL%d enable failed (%d)\n",
@@ -827,7 +828,8 @@
goto out;
/* Change the AXI bus frequency if we can. */
- if (strt_s->axiclk_khz != tgt_s->axiclk_khz) {
+ if (reason != SETRATE_PC &&
+ strt_s->axiclk_khz != tgt_s->axiclk_khz) {
res = clk_set_rate(drv_state.ebi1_clk,
tgt_s->axiclk_khz * 1000);
if (res < 0)
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index 631bd7e..0fccb64 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -112,8 +112,10 @@
{ }
};
+#define AVS(x) .avsdscr_setting = (x)
+
static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(0), 950000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(0), 950000, AVS(0x40001F) },
{ 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 975000 },
{ 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 975000 },
{ 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 1000000 },
@@ -126,20 +128,20 @@
{ 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(6), 1100000 },
{ 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(6), 1125000 },
{ 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(6), 1125000 },
- { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(18), 1175000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(18), 1175000 },
- { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(18), 1200000 },
- { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(18), 1200000 },
- { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(18), 1225000 },
- { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(18), 1225000 },
- { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(18), 1237500 },
- { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(18), 1237500 },
- { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(18), 1250000 },
+ { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(18), 1175000, AVS(0x400015) },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(18), 1175000, AVS(0x400015) },
+ { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(18), 1200000, AVS(0x400015) },
+ { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(18), 1200000, AVS(0x400015) },
+ { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(18), 1225000, AVS(0x400015) },
+ { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(18), 1225000, AVS(0x400015) },
+ { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(18), 1237500, AVS(0x400015) },
+ { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(18), 1237500, AVS(0x100018) },
+ { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(18), 1250000, AVS(0x400012) },
{ 0, { 0 } }
};
static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(0), 900000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(0), 900000, AVS(0x40007F) },
{ 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 925000 },
{ 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 925000 },
{ 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 950000 },
@@ -152,20 +154,20 @@
{ 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(6), 1050000 },
{ 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(6), 1075000 },
{ 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(6), 1075000 },
- { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(18), 1125000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(18), 1125000 },
- { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(18), 1150000 },
- { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(18), 1150000 },
- { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(18), 1175000 },
- { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(18), 1175000 },
- { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(18), 1187500 },
- { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(18), 1187500 },
- { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(18), 1200000 },
+ { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(18), 1125000, AVS(0x400015) },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(18), 1125000, AVS(0x400015) },
+ { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(18), 1150000, AVS(0x400015) },
+ { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(18), 1150000, AVS(0x400015) },
+ { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(18), 1175000, AVS(0x400015) },
+ { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(18), 1175000, AVS(0x400015) },
+ { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(18), 1187500, AVS(0x400015) },
+ { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(18), 1187500, AVS(0x100018) },
+ { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(18), 1200000, AVS(0x400012) },
{ 0, { 0 } }
};
static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(0), 850000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(0), 850000, AVS(0x4000FF) },
{ 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 875000 },
{ 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 875000 },
{ 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 900000 },
@@ -178,15 +180,15 @@
{ 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(6), 1000000 },
{ 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(6), 1025000 },
{ 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(6), 1025000 },
- { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(18), 1075000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(18), 1075000 },
- { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(18), 1100000 },
- { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(18), 1100000 },
- { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(18), 1125000 },
- { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(18), 1125000 },
- { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(18), 1137500 },
- { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(18), 1137500 },
- { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(18), 1150000 },
+ { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(18), 1075000, AVS(0x10001B) },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(18), 1075000, AVS(0x10001B) },
+ { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(18), 1100000, AVS(0x10001B) },
+ { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(18), 1100000, AVS(0x10001B) },
+ { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(18), 1125000, AVS(0x10001B) },
+ { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(18), 1125000, AVS(0x400012) },
+ { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(18), 1137500, AVS(0x400012) },
+ { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(18), 1137500, AVS(0x400012) },
+ { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(18), 1150000, AVS(0x400012) },
{ 0, { 0 } }
};
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index 9afa7c0..a487195 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -36,6 +36,7 @@
#include "acpuclock.h"
#include "acpuclock-krait.h"
+#include "avs.h"
/* MUX source selects. */
#define PRI_SRC_SEL_SEC_SRC 0
@@ -472,6 +473,12 @@
vdd_data.vdd_core = calculate_vdd_core(tgt);
vdd_data.ua_core = tgt->ua_core;
+ /* Disable AVS before voltage switch */
+ if (reason == SETRATE_CPUFREQ && drv.scalable[cpu].avs_enabled) {
+ AVS_DISABLE(cpu);
+ drv.scalable[cpu].avs_enabled = false;
+ }
+
/* Increase VDD levels if needed. */
if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG) {
rc = increase_vdd(cpu, &vdd_data, reason);
@@ -507,6 +514,12 @@
/* Drop VDD levels if we can. */
decrease_vdd(cpu, &vdd_data, reason);
+ /* Re-enable AVS */
+ if (reason == SETRATE_CPUFREQ && tgt->avsdscr_setting) {
+ AVS_ENABLE(cpu, tgt->avsdscr_setting);
+ drv.scalable[cpu].avs_enabled = true;
+ }
+
dev_dbg(drv.dev, "ACPU%d speed change complete\n", cpu);
out:
@@ -926,9 +939,11 @@
static void krait_apply_vmin(struct acpu_level *tbl)
{
- for (; tbl->speed.khz != 0; tbl++)
+ for (; tbl->speed.khz != 0; tbl++) {
if (tbl->vdd_core < 1150000)
tbl->vdd_core = 1150000;
+ tbl->avsdscr_setting = 0;
+ }
}
static int __init select_freq_plan(u32 qfprom_phys)
diff --git a/arch/arm/mach-msm/acpuclock-krait.h b/arch/arm/mach-msm/acpuclock-krait.h
index 1b891b1..352fef8 100644
--- a/arch/arm/mach-msm/acpuclock-krait.h
+++ b/arch/arm/mach-msm/acpuclock-krait.h
@@ -143,6 +143,7 @@
* @l2_level: L2 configuration to use.
* @vdd_core: CPU core voltage in uV.
* @ua_core: CPU core current consumption in uA.
+ * @avsdscr_setting: AVS DSCR configuration.
*/
struct acpu_level {
const int use_for_scaling;
@@ -150,6 +151,7 @@
const unsigned int l2_level;
int vdd_core;
int ua_core;
+ unsigned int avsdscr_setting;
};
/**
@@ -203,6 +205,7 @@
* @l2_vote: L2 performance level vote associate with the current CPU speed.
* @vreg: Array of voltage regulators needed by the scalable.
* @initialized: Flag set to true when per_cpu_init() has been called.
+ * @avs_enabled: True if avs is enabled for the scalabale. False otherwise.
*/
struct scalable {
const phys_addr_t hfpll_phys_base;
@@ -214,6 +217,7 @@
unsigned int l2_vote;
struct vreg vreg[NUM_VREG];
bool initialized;
+ bool avs_enabled;
};
/**
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 7c9f652..06efc03 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -1688,8 +1688,8 @@
.reg_base_addr = MSM_SAW0_BASE,
.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
#if defined(CONFIG_MSM_AVS_HW)
- .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x00,
- .reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
+ .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x50589464,
+ .reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00020000,
#endif
.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x03020004,
@@ -1703,8 +1703,8 @@
.reg_base_addr = MSM_SAW1_BASE,
.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
#if defined(CONFIG_MSM_AVS_HW)
- .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x00,
- .reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
+ .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x50589464,
+ .reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00020000,
#endif
.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index cd5b2e5..c877ba9 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -1728,7 +1728,7 @@
uint32_t quot;
/* This formula is as per chip characterization data */
- quot = max_quot - ((max_freq / 10 - new_freq / 10) * 5);
+ quot = max_quot - (((max_freq - new_freq) * 5) / 10);
return quot;
}
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 7dc8d0f..c82eac1 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -2096,7 +2096,7 @@
mutex_lock(&rt_entry->lock);
i += scnprintf(buf + i, max - i,
"Node Id: 0x%08x\n", rt_entry->node_id);
- if (j == IPC_ROUTER_NID_LOCAL) {
+ if (rt_entry->node_id == IPC_ROUTER_NID_LOCAL) {
i += scnprintf(buf + i, max - i,
"XPRT Name: Loopback\n");
i += scnprintf(buf + i, max - i,
diff --git a/arch/arm/mach-msm/msm_cpr.c b/arch/arm/mach-msm/msm_cpr.c
index e2640a2..12f7d96 100644
--- a/arch/arm/mach-msm/msm_cpr.c
+++ b/arch/arm/mach-msm/msm_cpr.c
@@ -44,6 +44,8 @@
*/
#define TIMER_COUNT(freq, delay) ((freq * delay) / 1000)
#define ALL_CPR_IRQ 0x3F
+#define STEP_QUOT_MAX 25
+#define STEP_QUOT_MIN 12
/* Need platform device handle for suspend and resume APIs */
static struct platform_device *cpr_pdev;
@@ -269,8 +271,19 @@
goto err_poll_result;
}
quot2 = (cpr_read_reg(cpr, RBCPR_DEBUG1) & QUOT_SLOW_M) >> 12;
- chip_data->step_quot = (quot1 - quot2) / 4;
- pr_info("%s: Calculated Step Quot is %d\n",
+ /*
+ * Based on chip characterization data, it is good to add some
+ * margin on top of calculated step quot to help reduce the
+ * number of CPR interrupts. The present value suggested is 3.
+ * Further, if the step quot is outside range, clamp it to the
+ * maximum permitted value.
+ */
+ chip_data->step_quot = ((quot1 - quot2) / 4) + 3;
+ if (chip_data->step_quot < STEP_QUOT_MIN ||
+ chip_data->step_quot > STEP_QUOT_MAX)
+ chip_data->step_quot = STEP_QUOT_MAX;
+
+ pr_info("%s: Step Quot is %d\n",
__func__, chip_data->step_quot);
/* Disable the cpr */
cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, DISABLE_CPR);
@@ -626,6 +639,8 @@
RBCPR_GCNT_TARGET(cpr->curr_osc)));
pr_debug("%s: new_freq: %d, set_freq: %d, quot: %d\n", __func__,
freqs->new, new_freq, quot);
+ pr_info("%s: PVS Voltage setting is: %d\n", __func__,
+ regulator_get_voltage(cpr->vreg_cx));
enable_irq(cpr->irq);
/**
diff --git a/arch/arm/mach-msm/ocmem_rdm.c b/arch/arm/mach-msm/ocmem_rdm.c
index 85dc85d..4aba69c 100644
--- a/arch/arm/mach-msm/ocmem_rdm.c
+++ b/arch/arm/mach-msm/ocmem_rdm.c
@@ -93,8 +93,8 @@
static void *br_base;
static void *dm_base;
-static atomic_t dm_pending;
-static wait_queue_head_t dm_wq;
+struct completion dm_clear_event;
+struct completion dm_transfer_event;
/* Shadow tables for debug purposes */
struct ocmem_br_table {
unsigned int offset;
@@ -136,22 +136,22 @@
pr_debug("Data mover completed\n");
irq_status &= ~BIT(0);
ocmem_write(irq_status, dm_base + DM_INTR_CLR);
+ complete(&dm_transfer_event);
} else if (irq_status & BIT(1)) {
pr_debug("Data clear engine completed\n");
irq_status &= ~BIT(1);
ocmem_write(irq_status, dm_base + DM_INTR_CLR);
+ complete(&dm_clear_event);
} else {
BUG_ON(1);
}
- atomic_set(&dm_pending, 0);
- wake_up_interruptible(&dm_wq);
return IRQ_HANDLED;
}
#ifdef CONFIG_MSM_OCMEM_NONSECURE
int ocmem_clear(unsigned long start, unsigned long size)
{
- atomic_set(&dm_pending, 1);
+ INIT_COMPLETION(dm_clear_event);
/* Clear DM Mask */
ocmem_write(DM_MASK_RESET, dm_base + DM_INTR_MASK);
/* Clear DM Interrupts */
@@ -169,8 +169,8 @@
/* Trigger Data Clear */
ocmem_write(DM_CLR_ENABLE, dm_base + DM_CLR_TRIGGER);
- wait_event_interruptible(dm_wq,
- atomic_read(&dm_pending) == 0);
+ wait_for_completion(&dm_clear_event);
+
return 0;
}
#else
@@ -249,7 +249,7 @@
status = ocmem_read(dm_base + DM_GEN_STATUS);
pr_debug("Transfer status before %x\n", status);
- atomic_set(&dm_pending, 1);
+ INIT_COMPLETION(dm_transfer_event);
/* The DM and BR tables must be programmed before triggering the
* Data Mover else the coherent transfer would be corrupted
*/
@@ -258,9 +258,7 @@
ocmem_write(dm_ctrl, dm_base + DM_CTRL);
pr_debug("ocmem: rdm: dm_ctrl %x br_ctrl %x\n", dm_ctrl, br_ctrl);
- wait_event_interruptible(dm_wq,
- atomic_read(&dm_pending) == 0);
-
+ wait_for_completion(&dm_transfer_event);
ocmem_disable_core_clock();
return 0;
}
@@ -291,7 +289,8 @@
return rc;
}
- init_waitqueue_head(&dm_wq);
+ init_completion(&dm_clear_event);
+ init_completion(&dm_transfer_event);
/* Clear DM Mask */
ocmem_write(DM_MASK_RESET, dm_base + DM_INTR_MASK);
/* enable dm interrupts */
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index 5962d71..30acebf 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -65,6 +65,7 @@
wait_queue_head_t ch_opened_wait_queue;
int i;
+ int ref_cnt;
int blocking_write;
int is_open;
@@ -270,6 +271,7 @@
if (!smd_pkt_devp)
return -EINVAL;
+ mutex_lock(&smd_pkt_devp->ch_lock);
switch (cmd) {
case TIOCMGET:
D_STATUS("%s TIOCMGET command on smd_pkt_dev id:%d\n",
@@ -288,6 +290,7 @@
pr_err("%s: Unrecognized ioctl command %d\n", __func__, cmd);
ret = -1;
}
+ mutex_unlock(&smd_pkt_devp->ch_lock);
return ret;
}
@@ -867,9 +870,12 @@
smd_pkt_devp->ch_size =
smd_write_avail(smd_pkt_devp->ch);
r = 0;
+ smd_pkt_devp->ref_cnt++;
D_STATUS("Finished %s on smd_pkt_dev id:%d\n",
__func__, smd_pkt_devp->i);
}
+ } else {
+ smd_pkt_devp->ref_cnt++;
}
release_pil:
if (peripheral && (r < 0))
@@ -902,12 +908,14 @@
D_STATUS("Begin %s on smd_pkt_dev id:%d\n",
__func__, smd_pkt_devp->i);
- clean_and_signal(smd_pkt_devp);
-
mutex_lock(&smd_pkt_devp->ch_lock);
mutex_lock(&smd_pkt_devp->rx_lock);
mutex_lock(&smd_pkt_devp->tx_lock);
- if (smd_pkt_devp->ch != 0) {
+ if (smd_pkt_devp->ref_cnt > 0)
+ smd_pkt_devp->ref_cnt--;
+
+ if (smd_pkt_devp->ch != 0 && smd_pkt_devp->ref_cnt == 0) {
+ clean_and_signal(smd_pkt_devp);
r = smd_close(smd_pkt_devp->ch);
smd_pkt_devp->ch = 0;
smd_pkt_devp->blocking_write = 0;
@@ -916,15 +924,15 @@
smd_pkt_devp->driver.probe = NULL;
if (smd_pkt_devp->pil)
pil_put(smd_pkt_devp->pil);
+ smd_pkt_devp->has_reset = 0;
+ smd_pkt_devp->do_reset_notification = 0;
+ smd_pkt_devp->wakelock_locked = 0;
+ wake_lock_destroy(&smd_pkt_devp->pa_wake_lock);
}
mutex_unlock(&smd_pkt_devp->tx_lock);
mutex_unlock(&smd_pkt_devp->rx_lock);
mutex_unlock(&smd_pkt_devp->ch_lock);
- smd_pkt_devp->has_reset = 0;
- smd_pkt_devp->do_reset_notification = 0;
- smd_pkt_devp->wakelock_locked = 0;
- wake_lock_destroy(&smd_pkt_devp->pa_wake_lock);
D_STATUS("Finished %s on smd_pkt_dev id:%d\n",
__func__, smd_pkt_devp->i);
diff --git a/arch/arm/mach-msm/spm-v2.c b/arch/arm/mach-msm/spm-v2.c
index 26dfdff..1eab9bf 100644
--- a/arch/arm/mach-msm/spm-v2.c
+++ b/arch/arm/mach-msm/spm-v2.c
@@ -310,9 +310,43 @@
return 0;
}
+#ifdef CONFIG_MSM_AVS_HW
+static void msm_spm_drv_disable_avs(struct msm_spm_driver_data *dev)
+{
+ msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_AVS_CTL);
+ dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] &= ~BIT(27);
+ msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_AVS_CTL);
+}
+
+static void msm_spm_drv_enable_avs(struct msm_spm_driver_data *dev)
+{
+ dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] |= BIT(27);
+ msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_AVS_CTL);
+}
+
+static void msm_spm_drv_set_avs_vlevel(struct msm_spm_driver_data *dev,
+ unsigned int vlevel)
+{
+ vlevel &= 0x3f;
+ dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] &= ~0x7efc00;
+ dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] |= ((vlevel - 4) << 10);
+ dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] |= (vlevel << 17);
+ msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_AVS_CTL);
+}
+
+#else
+
+static void msm_spm_drv_disable_avs(struct msm_spm_driver_data *dev) { }
+
+static void msm_spm_drv_enable_avs(struct msm_spm_driver_data *dev) { }
+
+static void msm_spm_drv_set_avs_vlevel(struct msm_spm_driver_data *dev,
+ unsigned int vlevel) { }
+#endif
+
int msm_spm_drv_set_vdd(struct msm_spm_driver_data *dev, unsigned int vlevel)
{
- uint32_t timeout_us;
+ uint32_t timeout_us, new_level;
if (!dev)
return -EINVAL;
@@ -321,42 +355,46 @@
return -ENOSYS;
if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
- pr_info("%s: requesting vlevel 0x%x\n",
- __func__, vlevel);
+ pr_info("%s: requesting vlevel %#x\n", __func__, vlevel);
+
+ msm_spm_drv_disable_avs(dev);
+
+ /* Kick the state machine back to idle */
+ dev->reg_shadow[MSM_SPM_REG_SAW2_RST] = 1;
+ msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_RST);
msm_spm_drv_apcs_set_vctl(dev, vlevel);
msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_VCTL);
msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_PMIC_DATA_0);
msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_PMIC_DATA_1);
- mb();
- /* Wait for PMIC state to return to idle or until timeout */
timeout_us = dev->vctl_timeout_us;
- while (msm_spm_drv_get_sts_pmic_state(dev) != MSM_SPM_PMIC_STATE_IDLE) {
- if (!timeout_us)
- goto set_vdd_bail;
-
- if (timeout_us > 10) {
- udelay(10);
- timeout_us -= 10;
- } else {
- udelay(timeout_us);
- timeout_us = 0;
- }
+ /* Confirm the voltage we set was what hardware sent */
+ do {
+ new_level = msm_spm_drv_get_sts_curr_pmic_data(dev);
+ if (new_level == vlevel)
+ break;
+ udelay(1);
+ } while (--timeout_us);
+ if (!timeout_us) {
+ pr_info("Wrong level %#x\n", new_level);
+ goto set_vdd_bail;
}
- if (msm_spm_drv_get_sts_curr_pmic_data(dev) != vlevel)
- goto set_vdd_bail;
+ /* Set AVS min/max */
+ msm_spm_drv_set_avs_vlevel(dev, vlevel);
if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
pr_info("%s: done, remaining timeout %uus\n",
__func__, timeout_us);
+ msm_spm_drv_enable_avs(dev);
return 0;
set_vdd_bail:
- pr_err("%s: failed, remaining timeout %uus, vlevel 0x%x\n",
- __func__, timeout_us, msm_spm_drv_get_sts_curr_pmic_data(dev));
+ msm_spm_drv_enable_avs(dev);
+ pr_err("%s: failed %#x, remaining timeout %uus, vlevel %#x\n",
+ __func__, vlevel, timeout_us, new_level);
return -EIO;
}
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 05d11d2..b87b0f1 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -38,16 +38,38 @@
uint32_t num_modes;
};
+struct msm_spm_vdd_info {
+ uint32_t cpu;
+ uint32_t vlevel;
+ int err;
+};
+
static struct msm_spm_device msm_spm_l2_device;
static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_spm_device, msm_cpu_spm_device);
-int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel)
+
+/* Must be called on the same cpu as the one being set to */
+static void msm_spm_smp_set_vdd(void *data)
{
struct msm_spm_device *dev;
- int ret = -EIO;
+ struct msm_spm_vdd_info *info = (struct msm_spm_vdd_info *)data;
- dev = &per_cpu(msm_cpu_spm_device, cpu);
- ret = msm_spm_drv_set_vdd(&dev->reg_data, vlevel);
+ dev = &per_cpu(msm_cpu_spm_device, info->cpu);
+ info->err = msm_spm_drv_set_vdd(&dev->reg_data, info->vlevel);
+}
+
+int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel)
+{
+ struct msm_spm_vdd_info info;
+ int ret;
+
+ info.cpu = cpu;
+ info.vlevel = vlevel;
+
+ /* Set to true to block on vdd change */
+ ret = smp_call_function_single(cpu, msm_spm_smp_set_vdd, &info, true);
+ if (!ret)
+ ret = info.err;
return ret;
}
diff --git a/drivers/hwmon/epm_adc.c b/drivers/hwmon/epm_adc.c
index 3969319..56b8841 100644
--- a/drivers/hwmon/epm_adc.c
+++ b/drivers/hwmon/epm_adc.c
@@ -102,8 +102,6 @@
#define EPM_PSOC_BUFFERED_DATA_LENGTH 48
#define EPM_PSOC_BUFFERED_DATA_LENGTH2 54
-#define EPM_SPI_NOR_CS_N_GPIO 53
-
struct epm_adc_drv {
struct platform_device *pdev;
struct device *hwmon;
@@ -172,14 +170,6 @@
{
int rc = 0;
- rc = gpio_request(EPM_SPI_NOR_CS_N_GPIO, "SPI_NOR_CS_N");
- if (!rc)
- gpio_direction_output(EPM_SPI_NOR_CS_N_GPIO, 1);
- else {
- pr_err("Configure spi nor Failed\n");
- return -EINVAL;
- }
-
if (epm_adc_first_request) {
rc = gpio_request(GPIO_EPM_GLOBAL_ENABLE, "EPM_GLOBAL_EN");
if (!rc) {
@@ -521,27 +511,27 @@
struct epm_adc_platform_data *pdata = epm_adc->pdev->dev.platform_data;
uint32_t chan_idx = (conv->device_idx * pdata->chan_per_adc) +
conv->channel_idx;
- int64_t *adc_scaled_data = 0;
+ int64_t adc_scaled_data = 0;
/* Get the channel number */
channel_num = (adc_raw_data[0] & EPM_ADC_ADS_CHANNEL_DATA_CHID);
sign_bit = 1;
/* This is the 16-bit raw data */
- *adc_scaled_data = ((adc_raw_data[1] << 8) | adc_raw_data[2]);
+ adc_scaled_data = ((adc_raw_data[1] << 8) | adc_raw_data[2]);
/* Obtain the internal system reading */
if (channel_num == EPM_ADC_ADS_CHANNEL_VCC) {
- *adc_scaled_data *= EPM_ADC_SCALE_MILLI;
- do_div(*adc_scaled_data, EPM_ADC_SCALE_CODE_VOLTS);
+ adc_scaled_data *= EPM_ADC_SCALE_MILLI;
+ do_div(adc_scaled_data, EPM_ADC_SCALE_CODE_VOLTS);
} else if (channel_num == EPM_ADC_ADS_CHANNEL_GAIN) {
- do_div(*adc_scaled_data, EPM_ADC_SCALE_CODE_GAIN);
+ do_div(adc_scaled_data, EPM_ADC_SCALE_CODE_GAIN);
} else if (channel_num == EPM_ADC_ADS_CHANNEL_REF) {
- *adc_scaled_data *= EPM_ADC_SCALE_MILLI;
- do_div(*adc_scaled_data, EPM_ADC_SCALE_CODE_VOLTS);
+ adc_scaled_data *= EPM_ADC_SCALE_MILLI;
+ do_div(adc_scaled_data, EPM_ADC_SCALE_CODE_VOLTS);
} else if (channel_num == EPM_ADC_ADS_CHANNEL_TEMP) {
/* Convert Code to micro-volts */
/* Use this formula to get the temperature reading */
- *adc_scaled_data -= EPM_ADC_TEMP_TO_DEGC_COEFF;
- do_div(*adc_scaled_data, EPM_ADC_TEMP_SENSOR_COEFF);
+ adc_scaled_data -= EPM_ADC_TEMP_TO_DEGC_COEFF;
+ do_div(adc_scaled_data, EPM_ADC_TEMP_SENSOR_COEFF);
} else if (channel_num == EPM_ADC_ADS_CHANNEL_OFFSET) {
/* The offset should be zero */
pr_debug("%s: ADC Channel Offset\n", __func__);
@@ -553,31 +543,31 @@
* mvVRef is in milli-volts and resistorvalue is in micro-ohms.
* Hence, I = V/R gives us current in kilo-amps.
*/
- if (*adc_scaled_data & EPM_ADC_MAX_NEGATIVE_SCALE_CODE) {
+ if (adc_scaled_data & EPM_ADC_MAX_NEGATIVE_SCALE_CODE) {
sign_bit = -1;
- *adc_scaled_data = (~*adc_scaled_data
+ adc_scaled_data = (~adc_scaled_data
& EPM_ADC_NEG_LSB_CODE);
}
- if (*adc_scaled_data != 0) {
- *adc_scaled_data *= EPM_ADC_SCALE_FACTOR;
+ if (adc_scaled_data != 0) {
+ adc_scaled_data *= EPM_ADC_SCALE_FACTOR;
/* Device is calibrated for 1LSB = VREF/7800h.*/
- *adc_scaled_data *= EPM_ADC_MILLI_VOLTS_SOURCE;
- do_div(*adc_scaled_data, EPM_ADC_VREF_CODE);
+ adc_scaled_data *= EPM_ADC_MILLI_VOLTS_SOURCE;
+ do_div(adc_scaled_data, EPM_ADC_VREF_CODE);
/* Data will now be in micro-volts.*/
- *adc_scaled_data *= EPM_ADC_SCALE_MILLI;
+ adc_scaled_data *= EPM_ADC_SCALE_MILLI;
/* Divide by amplifier gain value.*/
- do_div(*adc_scaled_data, pdata->channel[chan_idx].gain);
+ do_div(adc_scaled_data, pdata->channel[chan_idx].gain);
/* Data will now be in nano-volts.*/
- do_div(*adc_scaled_data, EPM_ADC_SCALE_FACTOR);
- *adc_scaled_data *= EPM_ADC_SCALE_MILLI;
+ do_div(adc_scaled_data, EPM_ADC_SCALE_FACTOR);
+ adc_scaled_data *= EPM_ADC_SCALE_MILLI;
/* Data is now in micro-amps.*/
- do_div(*adc_scaled_data,
+ do_div(adc_scaled_data,
pdata->channel[chan_idx].resistorvalue);
/* Set the sign bit for lekage current. */
- *adc_scaled_data *= sign_bit;
+ adc_scaled_data *= sign_bit;
}
}
- conv->physical = (int32_t) *adc_scaled_data;
+ conv->physical = (int32_t) adc_scaled_data;
return 0;
}
@@ -1600,16 +1590,15 @@
struct device_node *node = spi->dev.of_node;
int rc = 0;
- if (!node) {
- dev_err(&spi->dev, "no platform data?\n");
- pr_info("Error in the probe\n");
- return -EINVAL;
- }
-
if (node)
rc = get_device_tree_data(spi);
- else
- return -ENODEV;
+ else {
+ epm_adc = epm_adc_drv;
+ epm_adc_drv->epm_spi_client = spi;
+ epm_adc_drv->epm_spi_client->bits_per_word =
+ EPM_ADC_ADS_SPI_BITS_PER_WORD;
+ return rc;
+ }
epm_adc = epm_adc_drv;
epm_adc->misc.name = EPM_ADC_DRIVER_NAME;
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index c7269d3..ec9dac8 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/sched.h>
#include <linux/slab.h>
#include <media/msm_vidc.h>
#include "msm_vidc_internal.h"
@@ -23,21 +24,19 @@
#define MAX_EVENTS 30
-int msm_vidc_poll(void *instance, struct file *filp,
- struct poll_table_struct *wait)
+static int get_poll_flags(void *instance)
{
- int rc = 0;
struct msm_vidc_inst *inst = instance;
struct vb2_queue *outq = &inst->vb2_bufq[OUTPUT_PORT];
struct vb2_queue *capq = &inst->vb2_bufq[CAPTURE_PORT];
struct vb2_buffer *out_vb = NULL;
struct vb2_buffer *cap_vb = NULL;
unsigned long flags;
- poll_wait(filp, &inst->event_handler.wait, wait);
- poll_wait(filp, &capq->done_wq, wait);
- poll_wait(filp, &outq->done_wq, wait);
+ int rc = 0;
+
if (v4l2_event_pending(&inst->event_handler))
rc |= POLLPRI;
+
spin_lock_irqsave(&capq->done_lock, flags);
if (!list_empty(&capq->done_list))
cap_vb = list_first_entry(&capq->done_list, struct vb2_buffer,
@@ -46,6 +45,7 @@
|| cap_vb->state == VB2_BUF_STATE_ERROR))
rc |= POLLIN | POLLRDNORM;
spin_unlock_irqrestore(&capq->done_lock, flags);
+
spin_lock_irqsave(&outq->done_lock, flags);
if (!list_empty(&outq->done_list))
out_vb = list_first_entry(&outq->done_list, struct vb2_buffer,
@@ -54,6 +54,30 @@
|| out_vb->state == VB2_BUF_STATE_ERROR))
rc |= POLLOUT | POLLWRNORM;
spin_unlock_irqrestore(&outq->done_lock, flags);
+
+ return rc;
+}
+
+int msm_vidc_poll(void *instance, struct file *filp,
+ struct poll_table_struct *wait)
+{
+ struct msm_vidc_inst *inst = instance;
+ struct vb2_queue *outq = &inst->vb2_bufq[OUTPUT_PORT];
+ struct vb2_queue *capq = &inst->vb2_bufq[CAPTURE_PORT];
+
+ poll_wait(filp, &inst->event_handler.wait, wait);
+ poll_wait(filp, &capq->done_wq, wait);
+ poll_wait(filp, &outq->done_wq, wait);
+ return get_poll_flags(inst);
+}
+
+/* Kernel client alternative for msm_vidc_poll */
+int msm_vidc_wait(void *instance)
+{
+ struct msm_vidc_inst *inst = instance;
+ int rc = 0;
+
+ wait_event(inst->kernel_event_queue, (rc = get_poll_flags(inst)));
return rc;
}
@@ -385,8 +409,10 @@
INIT_LIST_HEAD(&inst->pendingq);
INIT_LIST_HEAD(&inst->internalbufs);
INIT_LIST_HEAD(&inst->persistbufs);
+ init_waitqueue_head(&inst->kernel_event_queue);
inst->state = MSM_VIDC_CORE_UNINIT_DONE;
inst->core = core;
+
for (i = SESSION_MSG_INDEX(SESSION_MSG_START);
i <= SESSION_MSG_INDEX(SESSION_MSG_END); i++) {
init_completion(&inst->completions[i]);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index 84552a4..7f3096a 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -408,6 +408,7 @@
inst->reconfig_width = event_notify->width;
inst->in_reconfig = true;
v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+ wake_up(&inst->kernel_event_queue);
return;
} else {
dprintk(VIDC_ERR,
@@ -501,6 +502,7 @@
dqevent.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
dqevent.id = 0;
v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+ wake_up(&inst->kernel_event_queue);
} else {
dprintk(VIDC_ERR, "Failed to get valid response for flush\n");
}
@@ -518,6 +520,7 @@
dqevent.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
dqevent.id = 0;
v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+ wake_up(&inst->kernel_event_queue);
} else {
dprintk(VIDC_ERR,
"Failed to get valid response for session close\n");
@@ -552,13 +555,17 @@
{
struct msm_vidc_cb_data_done *response = data;
struct vb2_buffer *vb;
+ struct msm_vidc_inst *inst;
if (!response) {
dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
return;
}
vb = response->clnt_data;
- if (vb)
+ inst = (struct msm_vidc_inst *)response->session_id;
+ if (vb) {
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ wake_up(&inst->kernel_event_queue);
+ }
}
static void handle_fbd(enum command_response cmd, void *data)
@@ -622,6 +629,7 @@
vb->v4l2_planes[0].bytesused,
vb->v4l2_buf.flags);
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ wake_up(&inst->kernel_event_queue);
} else {
/*
* FIXME:
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index 3c14123..1f2eff8 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -19,6 +19,7 @@
#include <linux/types.h>
#include <linux/completion.h>
#include <linux/clk.h>
+#include <linux/wait.h>
#include <mach/msm_bus.h>
#include <mach/msm_bus_board.h>
#include <mach/ocmem.h>
@@ -226,6 +227,7 @@
struct completion completions[SESSION_MSG_END - SESSION_MSG_START + 1];
struct v4l2_fh event_handler;
struct msm_smem *extradata_handle;
+ wait_queue_head_t kernel_event_queue;
bool in_reconfig;
u32 reconfig_width;
u32 reconfig_height;
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index 28abb36..48532e5 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -340,6 +340,7 @@
return -EINVAL;
}
+ vb->v4l2_buf.timestamp = b->timestamp;
list_add_tail(&vb->queued_entry, &q->queued_list);
vb->state = VB2_BUF_STATE_QUEUED;
diff --git a/drivers/media/video/vcap_vc.c b/drivers/media/video/vcap_vc.c
index 78e108f..5ae362f 100644
--- a/drivers/media/video/vcap_vc.c
+++ b/drivers/media/video/vcap_vc.c
@@ -122,6 +122,17 @@
return 0;
}
+static struct timeval interpolate_ts(struct timeval tv, uint32_t delta)
+{
+ if (tv.tv_usec < delta) {
+ tv.tv_sec--;
+ tv.tv_usec += VCAP_USEC - delta;
+ } else {
+ tv.tv_usec -= delta;
+ }
+ return tv;
+}
+
irqreturn_t vc_handler(struct vcap_dev *dev)
{
uint32_t irq, timestamp;
@@ -212,6 +223,20 @@
/* If here we know which buffers are done */
timestamp = readl_relaxed(VCAP_VC_TIMESTAMP);
+ if (timestamp < c_data->vc_action.last_ts) {
+ c_data->vc_action.vc_ts.tv_usec +=
+ (0xFFFFFFFF - c_data->vc_action.last_ts) +
+ timestamp + 1;
+ } else {
+ c_data->vc_action.vc_ts.tv_usec +=
+ timestamp - c_data->vc_action.last_ts;
+ }
+
+ c_data->vc_action.vc_ts.tv_sec +=
+ c_data->vc_action.vc_ts.tv_usec / VCAP_USEC;
+ c_data->vc_action.vc_ts.tv_usec =
+ c_data->vc_action.vc_ts.tv_usec % VCAP_USEC;
+ c_data->vc_action.last_ts = timestamp;
c_data->vc_action.buf_num = (buf_num + done_count) % tot;
for (i = 0; i < done_count; i++) {
@@ -232,9 +257,10 @@
/* Config vc with this new buffer */
config_buffer(c_data, buf, VCAP_VC_Y_ADDR_1 + 0x8 * idx,
VCAP_VC_C_ADDR_1 + 0x8 * idx);
- vb->v4l2_buf.timestamp.tv_usec = timestamp -
+ vb->v4l2_buf.timestamp = interpolate_ts(
+ c_data->vc_action.vc_ts,
1000000 / c_data->vc_format.frame_rate *
- (done_count - 1 - i);
+ (done_count - 1 - i));
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
work_todo = true;
c_data->vc_action.buf[idx] = buf;
@@ -298,6 +324,12 @@
VCAP_VC_C_ADDR_1 + i * 8);
}
+ c_data->vc_action.last_ts = readl_relaxed(VCAP_VC_TIMESTAMP);
+ c_data->vc_action.vc_ts.tv_sec =
+ c_data->vc_action.last_ts / VCAP_USEC;
+ c_data->vc_action.vc_ts.tv_usec =
+ c_data->vc_action.last_ts % VCAP_USEC;
+
rc = 0;
for (i = 0; i < c_data->vc_action.tot_buf; i++)
rc = rc << 1 | 0x2;
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index 139de28..c81206f 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -233,6 +233,10 @@
queue_work(dev->vcap_wq, &dev->vp_to_vc_work.work);
}
+ if (vp_act->bufT0 != NULL && vp_act->vp_state == VP_NORMAL) {
+ vp_act->bufOut->vb.v4l2_buf.timestamp =
+ vp_act->bufT0->vb.v4l2_buf.timestamp;
+ }
vb2_buffer_done(&vp_act->bufOut->vb, VB2_BUF_STATE_DONE);
/* Cycle to next state */
diff --git a/drivers/video/msm/mhl/mhl_8334.c b/drivers/video/msm/mhl/mhl_8334.c
index f3b8cd1..6c0778f 100644
--- a/drivers/video/msm/mhl/mhl_8334.c
+++ b/drivers/video/msm/mhl/mhl_8334.c
@@ -62,6 +62,9 @@
void (*notify_usb_online)(int online);
static void mhl_drive_hpd(uint8_t to_state);
static int mhl_send_msc_command(struct msc_command_struct *req);
+static void list_cmd_put(struct msc_command_struct *cmd);
+static struct msc_command_struct *list_cmd_get(void);
+static void mhl_msc_send_work(struct work_struct *work);
static struct i2c_driver mhl_sii_i2c_driver = {
.driver = {
@@ -618,7 +621,7 @@
list_add_tail(&new_cmd->msc_queue_envelope, &mhl_msm_state->list_cmd);
}
-struct msc_command_struct *list_cmd_get(void)
+static struct msc_command_struct *list_cmd_get(void)
{
struct msc_cmd_envelope *cmd_env =
list_first_entry(&mhl_msm_state->list_cmd,
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index cfca799..34464c6 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -68,4 +68,5 @@
int msm_vidc_unsubscribe_event(void *instance,
struct v4l2_event_subscription *sub);
int msm_vidc_dqevent(void *instance, struct v4l2_event *event);
+int msm_vidc_wait(void *instance);
#endif
diff --git a/include/media/vcap_v4l2.h b/include/media/vcap_v4l2.h
index 1e18c9e..7b6d817 100644
--- a/include/media/vcap_v4l2.h
+++ b/include/media/vcap_v4l2.h
@@ -38,6 +38,7 @@
writel_relaxed(val, addr); \
} while (0)
+#define VCAP_USEC (1000000)
#define VCAP_BASE (dev->vcapbase)
#define VCAP_OFFSET(off) (VCAP_BASE + off)
@@ -87,6 +88,9 @@
uint8_t tot_buf;
uint8_t buf_num;
+ struct timeval vc_ts;
+ uint32_t last_ts;
+
/* Buffers inside vc */
struct vcap_buffer *buf[6];
};