Merge "msm: msm_watchdog: Don't pet the watchdog if it isn't enabled" into msm-3.0
diff --git a/arch/arm/boot/dts/msmcopper-regulator.dtsi b/arch/arm/boot/dts/msmcopper-regulator.dtsi
index 4d9f10e..b0c48fc 100644
--- a/arch/arm/boot/dts/msmcopper-regulator.dtsi
+++ b/arch/arm/boot/dts/msmcopper-regulator.dtsi
@@ -24,16 +24,16 @@
};
pm8941_s2: regulator@1700 {
- regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
+ regulator-min-microvolt = <2150000>;
+ regulator-max-microvolt = <2150000>;
qcom,enable-time = <500>;
qcom,pull-down-enable = <1>;
status = "okay";
};
pm8941_s3: regulator@1a00 {
- regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
qcom,enable-time = <500>;
qcom,pull-down-enable = <1>;
status = "okay";
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 4e43cb2..1107412 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -214,6 +214,9 @@
void __iomem *base = gic_data_dist_base(gic);
for (i = 0; i * 32 < gic->max_irq; i++) {
+#ifdef CONFIG_ARCH_MSM8625
+ raw_spin_lock(&irq_controller_lock);
+#endif
gic->enabled_irqs[i]
= readl_relaxed(base + GIC_DIST_ENABLE_SET + i * 4);
/* disable all of them */
@@ -221,6 +224,9 @@
/* enable the wakeup set */
writel_relaxed(gic->wakeup_irqs[i],
base + GIC_DIST_ENABLE_SET + i * 4);
+#ifdef CONFIG_ARCH_MSM8625
+ raw_spin_unlock(&irq_controller_lock);
+#endif
}
mb();
return 0;
@@ -269,11 +275,17 @@
gic_show_resume_irq(gic);
for (i = 0; i * 32 < gic->max_irq; i++) {
+#ifdef CONFIG_ARCH_MSM8625
+ raw_spin_lock(&irq_controller_lock);
+#endif
/* disable all of them */
writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4);
/* enable the enabled set */
writel_relaxed(gic->enabled_irqs[i],
base + GIC_DIST_ENABLE_SET + i * 4);
+#ifdef CONFIG_ARCH_MSM8625
+ raw_spin_unlock(&irq_controller_lock);
+#endif
}
mb();
}
@@ -306,8 +318,13 @@
gic_arch_extn.irq_eoi(d);
raw_spin_unlock(&irq_controller_lock);
}
-
+#ifdef CONFIG_ARCH_MSM8625
+ raw_spin_lock(&irq_controller_lock);
+#endif
writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
+#ifdef CONFIG_ARCH_MSM8625
+ raw_spin_unlock(&irq_controller_lock);
+#endif
}
static int gic_set_type(struct irq_data *d, unsigned int type)
@@ -430,7 +447,13 @@
void __iomem *cpu_base = gic_data_cpu_base(gic);
do {
+#ifdef CONFIG_ARCH_MSM8625
+ raw_spin_lock(&irq_controller_lock);
+#endif
irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+#ifdef CONFIG_ARCH_MSM8625
+ raw_spin_unlock(&irq_controller_lock);
+#endif
irqnr = irqstat & ~0x1c00;
if (likely(irqnr > 15 && irqnr < 1021)) {
@@ -439,7 +462,13 @@
continue;
}
if (irqnr < 16) {
+#ifdef CONFIG_ARCH_MSM8625
+ raw_spin_lock(&irq_controller_lock);
+#endif
writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+#ifdef CONFIG_ARCH_MSM8625
+ raw_spin_unlock(&irq_controller_lock);
+#endif
#ifdef CONFIG_SMP
handle_IPI(irqnr, regs);
#endif
@@ -588,6 +617,9 @@
* Deal with the banked PPI and SGI interrupts - disable all
* PPI interrupts, ensure all SGI interrupts are enabled.
*/
+#ifdef CONFIG_ARCH_MSM8625
+ raw_spin_lock(&irq_controller_lock);
+#endif
writel_relaxed(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
writel_relaxed(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
@@ -607,6 +639,9 @@
writel_relaxed(0xF, base + GIC_CPU_CTRL);
else
writel_relaxed(1, base + GIC_CPU_CTRL);
+#ifdef CONFIG_ARCH_MSM8625
+ raw_spin_unlock(&irq_controller_lock);
+#endif
mb();
}
@@ -944,6 +979,9 @@
int cpu;
unsigned long sgir;
unsigned long map = 0;
+#ifdef CONFIG_ARCH_MSM8625
+ unsigned long flags;
+#endif
/* Convert our logical CPU mask into a physical one. */
for_each_cpu(cpu, mask)
@@ -959,9 +997,15 @@
*/
dsb();
+#ifdef CONFIG_ARCH_MSM8625
+ raw_spin_lock_irqsave(&irq_controller_lock, flags);
+#endif
/* this always happens on GIC0 */
writel_relaxed(sgir,
gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+#ifdef CONFIG_ARCH_MSM8625
+ raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+#endif
mb();
}
#endif
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index 1574a54..64451eb 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -42,6 +42,7 @@
CONFIG_MSM_IPC_ROUTER=y
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
# CONFIG_MSM_HW3D is not set
+CONFIG_MSM_PIL_LPASS_QDSP6V5=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index 2019f9b..24f0f41 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -430,6 +430,19 @@
.vcm_enable = 0,
};
+static struct i2c_board_info msm_act_main_cam1_i2c_info = {
+ I2C_BOARD_INFO("msm_actuator", 0x18),
+};
+
+static struct msm_actuator_info msm_act_main_cam_1_info = {
+ .board_info = &msm_act_main_cam1_i2c_info,
+ .cam_name = MSM_ACTUATOR_MAIN_CAM_1,
+ .bus_id = APQ_8064_GSBI4_QUP_I2C_BUS_ID,
+ .vcm_pwd = 0,
+ .vcm_enable = 0,
+};
+
+
static struct msm_camera_i2c_conf apq8064_front_cam_i2c_conf = {
.use_i2c_mux = 1,
.mux_dev = &msm8960_device_i2c_mux_gsbi4,
@@ -498,6 +511,7 @@
.csi_if = 1,
.camera_type = BACK_CAMERA_2D,
.sensor_type = BAYER_SENSOR,
+ .actuator_info = &msm_act_main_cam_1_info,
};
static struct camera_vreg_t apq_8064_s5k3l1yx_vreg[] = {
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index b60519b..83e3c8d 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -492,6 +492,18 @@
.vcm_enable = 0,
};
+static struct i2c_board_info msm_act_main_cam1_i2c_info = {
+ I2C_BOARD_INFO("msm_actuator", 0x18),
+};
+
+static struct msm_actuator_info msm_act_main_cam_1_info = {
+ .board_info = &msm_act_main_cam1_i2c_info,
+ .cam_name = MSM_ACTUATOR_MAIN_CAM_1,
+ .bus_id = MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+ .vcm_pwd = 0,
+ .vcm_enable = 0,
+};
+
static struct msm_camera_sensor_flash_data flash_imx074 = {
.flash_type = MSM_CAMERA_FLASH_LED,
#ifdef CONFIG_MSM_CAMERA_FLASH
@@ -654,6 +666,7 @@
.csi_if = 1,
.camera_type = BACK_CAMERA_2D,
.sensor_type = BAYER_SENSOR,
+ .actuator_info = &msm_act_main_cam_1_info,
};
static struct pm8xxx_mpp_config_data privacy_light_on_config = {
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index ccfc770..d1b62ae 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -337,9 +337,14 @@
},
};
+static struct smd_subsystem_restart_config smd_ssr_cfg = {
+ .disable_smsm_reset_handshake = 1,
+};
+
static struct smd_platform smd_platform_data = {
.num_ss_configs = ARRAY_SIZE(smd_config_list),
.smd_ss_configs = smd_config_list,
+ .smd_ssr_config = &smd_ssr_cfg,
.num_smem_areas = ARRAY_SIZE(aux_smem_areas),
.smd_smem_areas = aux_smem_areas,
};
diff --git a/arch/arm/mach-msm/board-msm7627a-display.c b/arch/arm/mach-msm/board-msm7627a-display.c
index af3d187..2a703f0 100644
--- a/arch/arm/mach-msm/board-msm7627a-display.c
+++ b/arch/arm/mach-msm/board-msm7627a-display.c
@@ -581,83 +581,83 @@
int i = 0;
int remainder;
/* device address byte = 0x72 */
- gpio_set_value_cansleep(96, 0);
+ gpio_set_value(96, 0);
udelay(67);
- gpio_set_value_cansleep(96, 1);
+ gpio_set_value(96, 1);
udelay(33);
- gpio_set_value_cansleep(96, 0);
+ gpio_set_value(96, 0);
udelay(33);
- gpio_set_value_cansleep(96, 1);
+ gpio_set_value(96, 1);
udelay(67);
- gpio_set_value_cansleep(96, 0);
+ gpio_set_value(96, 0);
udelay(33);
- gpio_set_value_cansleep(96, 1);
+ gpio_set_value(96, 1);
udelay(67);
- gpio_set_value_cansleep(96, 0);
+ gpio_set_value(96, 0);
udelay(33);
- gpio_set_value_cansleep(96, 1);
+ gpio_set_value(96, 1);
udelay(67);
- gpio_set_value_cansleep(96, 0);
+ gpio_set_value(96, 0);
udelay(67);
- gpio_set_value_cansleep(96, 1);
+ gpio_set_value(96, 1);
udelay(33);
- gpio_set_value_cansleep(96, 0);
+ gpio_set_value(96, 0);
udelay(67);
- gpio_set_value_cansleep(96, 1);
+ gpio_set_value(96, 1);
udelay(33);
- gpio_set_value_cansleep(96, 0);
+ gpio_set_value(96, 0);
udelay(33);
- gpio_set_value_cansleep(96, 1);
+ gpio_set_value(96, 1);
udelay(67);
- gpio_set_value_cansleep(96, 0);
+ gpio_set_value(96, 0);
udelay(67);
- gpio_set_value_cansleep(96, 1);
+ gpio_set_value(96, 1);
udelay(33);
/* t-EOS and t-start */
- gpio_set_value_cansleep(96, 0);
+ gpio_set_value(96, 0);
ndelay(4200);
- gpio_set_value_cansleep(96, 1);
+ gpio_set_value(96, 1);
ndelay(9000);
/* data byte */
/* RFA = 0 */
- gpio_set_value_cansleep(96, 0);
+ gpio_set_value(96, 0);
udelay(67);
- gpio_set_value_cansleep(96, 1);
+ gpio_set_value(96, 1);
udelay(33);
/* Address bits */
- gpio_set_value_cansleep(96, 0);
+ gpio_set_value(96, 0);
udelay(67);
- gpio_set_value_cansleep(96, 1);
+ gpio_set_value(96, 1);
udelay(33);
- gpio_set_value_cansleep(96, 0);
+ gpio_set_value(96, 0);
udelay(67);
- gpio_set_value_cansleep(96, 1);
+ gpio_set_value(96, 1);
udelay(33);
/* Data bits */
for (i = 0; i < 5; i++) {
remainder = (level) & (16);
if (remainder) {
- gpio_set_value_cansleep(96, 0);
+ gpio_set_value(96, 0);
udelay(33);
- gpio_set_value_cansleep(96, 1);
+ gpio_set_value(96, 1);
udelay(67);
} else {
- gpio_set_value_cansleep(96, 0);
+ gpio_set_value(96, 0);
udelay(67);
- gpio_set_value_cansleep(96, 1);
+ gpio_set_value(96, 1);
udelay(33);
}
level = level << 1;
}
/* t-EOS */
- gpio_set_value_cansleep(96, 0);
+ gpio_set_value(96, 0);
ndelay(12000);
- gpio_set_value_cansleep(96, 1);
+ gpio_set_value(96, 1);
return 0;
}
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 2ed5897..8941b6d 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -48,7 +48,6 @@
#include <mach/msm_battery.h>
#include <linux/smsc911x.h>
#include <linux/atmel_maxtouch.h>
-#include <linux/fmem.h>
#include <linux/msm_adc.h>
#include "devices.h"
#include "timer.h"
@@ -436,9 +435,6 @@
.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
.cached = 1,
.memory_type = MEMTYPE_EBI1,
- .request_region = request_fmem_c_region,
- .release_region = release_fmem_c_region,
- .reusable = 1,
};
static struct platform_device android_pmem_adsp_device = {
@@ -760,14 +756,6 @@
static void msm7x27a_cfg_uart2dm_serial(void) { }
#endif
-struct fmem_platform_data fmem_pdata;
-
-struct platform_device fmem_device = {
- .name = "fmem",
- .id = -1,
- .dev = { .platform_data = &fmem_pdata },
-};
-
static struct platform_device *rumi_sim_devices[] __initdata = {
&msm_device_dmov,
&msm_device_smd,
@@ -805,7 +793,6 @@
&android_pmem_device,
&android_pmem_adsp_device,
&android_pmem_audio_device,
- &fmem_device,
&msm_device_nand,
&msm_device_snd,
&msm_device_adspdec,
@@ -856,19 +843,8 @@
},
};
-#ifdef CONFIG_ANDROID_PMEM
-static struct android_pmem_platform_data *pmem_pdata_array[] __initdata = {
- &android_pmem_adsp_pdata,
- &android_pmem_audio_pdata,
- &android_pmem_pdata,
-};
-#endif
-
static void __init size_pmem_devices(void)
{
-#ifdef CONFIG_ANDROID_PMEM
- unsigned int i;
- unsigned int reusable_count = 0;
if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) {
pmem_mdp_size = MSM7x25A_MSM_PMEM_MDP_SIZE;
@@ -878,30 +854,11 @@
pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
}
+#ifdef CONFIG_ANDROID_PMEM
android_pmem_adsp_pdata.size = pmem_adsp_size;
android_pmem_pdata.size = pmem_mdp_size;
android_pmem_audio_pdata.size = pmem_audio_size;
-
- fmem_pdata.size = 0;
-
- /* Find pmem devices that should use FMEM (reusable) memory.
- */
- for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i) {
- struct android_pmem_platform_data *pdata = pmem_pdata_array[i];
-
- if (!reusable_count && pdata->reusable)
- fmem_pdata.size += pdata->size;
-
- reusable_count += (pdata->reusable) ? 1 : 0;
-
- if (pdata->reusable && reusable_count > 1) {
- pr_err("%s: Too many PMEM devices specified as reusable. PMEM device %s was not configured as reusable.\n",
- __func__, pdata->name);
- pdata->reusable = 0;
- }
- }
#endif
-
}
static void __init reserve_memory_for(struct android_pmem_platform_data *p)
@@ -912,12 +869,9 @@
static void __init reserve_pmem_memory(void)
{
#ifdef CONFIG_ANDROID_PMEM
- unsigned int i;
- for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i) {
- if (!pmem_pdata_array[i]->reusable)
- reserve_memory_for(pmem_pdata_array[i]);
- }
-
+ reserve_memory_for(&android_pmem_adsp_pdata);
+ reserve_memory_for(&android_pmem_pdata);
+ reserve_memory_for(&android_pmem_audio_pdata);
msm7x27a_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
#endif
}
@@ -943,7 +897,6 @@
{
reserve_info = &msm7x27a_reserve_info;
msm_reserve();
- fmem_pdata.phys = reserve_memory_for_fmem(fmem_pdata.size);
}
static void __init msm8625_reserve(void)
diff --git a/arch/arm/mach-msm/devices-msm7x27.c b/arch/arm/mach-msm/devices-msm7x27.c
index 5ec339e..d36b8d9 100644
--- a/arch/arm/mach-msm/devices-msm7x27.c
+++ b/arch/arm/mach-msm/devices-msm7x27.c
@@ -427,7 +427,7 @@
.exit_sleep3 = msm_irq_exit_sleep3,
};
-void msm_pm_register_irqs(void)
+void __init msm_pm_register_irqs(void)
{
msm_pm_set_irq_extns(&msm7x27_pm_irq_calls);
}
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 1391981..bd0376e 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -447,7 +447,7 @@
.exit_sleep3 = msm_gic_irq_exit_sleep3,
};
-void msm_pm_register_irqs(void)
+void __init msm_pm_register_irqs(void)
{
if (cpu_is_msm8625())
msm_pm_set_irq_extns(&msm8625_pm_irq_calls);
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index 0e15a4f..5f08d77 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -681,7 +681,7 @@
.exit_sleep3 = msm_irq_exit_sleep3,
};
-void msm_pm_register_irqs(void)
+void __init msm_pm_register_irqs(void)
{
msm_pm_set_irq_extns(&msm7x30_pm_irq_calls);
}
diff --git a/arch/arm/mach-msm/devices-qsd8x50.c b/arch/arm/mach-msm/devices-qsd8x50.c
index a32079b..674d55c 100644
--- a/arch/arm/mach-msm/devices-qsd8x50.c
+++ b/arch/arm/mach-msm/devices-qsd8x50.c
@@ -443,7 +443,7 @@
.exit_sleep3 = msm_irq_exit_sleep3,
};
-void msm_pm_register_irqs(void)
+void __init msm_pm_register_irqs(void)
{
msm_pm_set_irq_extns(&qsd8x50_pm_irq_calls);
}
diff --git a/arch/arm/mach-msm/headsmp.S b/arch/arm/mach-msm/headsmp.S
index 979c1f8..1602811 100644
--- a/arch/arm/mach-msm/headsmp.S
+++ b/arch/arm/mach-msm/headsmp.S
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2003 ARM Limited
* All Rights Reserved
- * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2010, 2012 Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -10,6 +10,8 @@
#include <linux/linkage.h>
#include <linux/init.h>
+__CPUINIT
+
/*
* MSM specific entry point for secondary CPUs. This provides
* a "holding pen" into which all secondary cores are held until we're
diff --git a/arch/arm/mach-msm/idle_stats_device.c b/arch/arm/mach-msm/idle_stats_device.c
index d5a61af..3c0e7a9 100644
--- a/arch/arm/mach-msm/idle_stats_device.c
+++ b/arch/arm/mach-msm/idle_stats_device.c
@@ -103,9 +103,10 @@
{
hrtimer_cancel(&device->busy_timer);
hrtimer_set_expires(&device->busy_timer, us_to_ktime(0));
- if (device->stats->nr_collected >= device->max_samples)
- return;
-
+ if (device->stats->nr_collected >= MSM_IDLE_STATS_NR_MAX_INTERVALS) {
+ pr_warning("idle_stats_device: Overwriting samples\n");
+ device->stats->nr_collected = 0;
+ }
device->stats->pulse_chain[device->stats->nr_collected] = *pulse;
device->stats->nr_collected++;
@@ -230,6 +231,7 @@
void msm_idle_stats_idle_end(struct msm_idle_stats_device *device,
struct msm_idle_pulse *pulse)
{
+ int tmp;
u32 idle_time = 0;
spin_lock(&device->lock);
if (ktime_to_us(device->idle_start) != 0) {
@@ -254,7 +256,18 @@
ktime_to_us(busy_timer)))
busy_timer = device->remaining_time;
start_busy_timer(device, busy_timer);
- }
+ /* If previous busy interval exceeds the current submit,
+ * raise a busy timer expired event intentionally.
+ */
+ tmp = device->stats->nr_collected - 1;
+ if (tmp > 0) {
+ if ((device->stats->pulse_chain[tmp - 1].busy_start_time
+ + device->stats->pulse_chain[tmp - 1].busy_interval) >
+ device->stats->pulse_chain[tmp].busy_start_time)
+ msm_idle_stats_update_event(device,
+ MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED);
+ }
+ }
}
spin_unlock(&device->lock);
}
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h
index fb7f977..339a955 100644
--- a/arch/arm/mach-msm/include/mach/dma.h
+++ b/arch/arm/mach-msm/include/mach/dma.h
@@ -1,7 +1,7 @@
/* linux/include/asm-arm/arch-msm/dma.h
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -255,10 +255,10 @@
#endif
/* channels for APQ8064 */
-#define DMOV8064_CE_IN_CHAN 2
+#define DMOV8064_CE_IN_CHAN 0
#define DMOV8064_CE_IN_CRCI 14
-#define DMOV8064_CE_OUT_CHAN 3
+#define DMOV8064_CE_OUT_CHAN 1
#define DMOV8064_CE_OUT_CRCI 15
diff --git a/arch/arm/mach-msm/mpm-8625.c b/arch/arm/mach-msm/mpm-8625.c
index 8ef7d61..6b88103 100644
--- a/arch/arm/mach-msm/mpm-8625.c
+++ b/arch/arm/mach-msm/mpm-8625.c
@@ -175,7 +175,7 @@
}
#endif
-void msm_gic_irq_extn_init(void __iomem *db, void __iomem *cb)
+void __init msm_gic_irq_extn_init(void __iomem *db, void __iomem *cb)
{
dist_base = db;
cpu_base = cb;
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index c237013..a22b175 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -650,7 +650,7 @@
}
#endif
-static bool msm_pm_spm_power_collapse(
+static bool __ref msm_pm_spm_power_collapse(
unsigned int cpu, bool from_idle, bool notify_rpm)
{
void *entry;
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index 4f3c7e4..39e321a 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -1410,7 +1410,7 @@
* Return value:
* 0: success
*/
-static int msm_pm_power_collapse_standalone(bool from_idle)
+static int __ref msm_pm_power_collapse_standalone(bool from_idle)
{
int collapsed = 0;
int ret;
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index 430a4c0..abcd336 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -287,7 +287,6 @@
int bytes_read;
int pkt_size;
struct smd_pkt_dev *smd_pkt_devp;
- struct smd_channel *chl;
unsigned long flags;
smd_pkt_devp = file->private_data;
@@ -312,20 +311,30 @@
D_READ("Begin %s on smd_pkt_dev id:%d buffer_size %d\n",
__func__, smd_pkt_devp->i, count);
- chl = smd_pkt_devp->ch;
wait_for_packet:
r = wait_event_interruptible(smd_pkt_devp->ch_read_wait_queue,
- (smd_cur_packet_size(chl) > 0 &&
- smd_read_avail(chl)) ||
+ !smd_pkt_devp->ch ||
+ (smd_cur_packet_size(smd_pkt_devp->ch) > 0
+ && smd_read_avail(smd_pkt_devp->ch)) ||
smd_pkt_devp->has_reset);
+ mutex_lock(&smd_pkt_devp->rx_lock);
if (smd_pkt_devp->has_reset) {
+ mutex_unlock(&smd_pkt_devp->rx_lock);
pr_err("%s notifying reset for smd_pkt_dev id:%d\n",
__func__, smd_pkt_devp->i);
return notify_reset(smd_pkt_devp);
}
+ if (!smd_pkt_devp->ch) {
+ mutex_unlock(&smd_pkt_devp->rx_lock);
+ pr_err("%s on a closed smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
+ return -EINVAL;
+ }
+
if (r < 0) {
+ mutex_unlock(&smd_pkt_devp->rx_lock);
/* qualify error message */
if (r != -ERESTARTSYS) {
/* we get this anytime a signal comes in */
@@ -337,8 +346,6 @@
}
/* Here we have a whole packet waiting for us */
-
- mutex_lock(&smd_pkt_devp->rx_lock);
pkt_size = smd_cur_packet_size(smd_pkt_devp->ch);
if (!pkt_size) {
@@ -429,7 +436,7 @@
return -EINVAL;
}
- if (smd_pkt_devp->do_reset_notification) {
+ if (smd_pkt_devp->do_reset_notification || smd_pkt_devp->has_reset) {
pr_err("%s notifying reset for smd_pkt_dev id:%d\n",
__func__, smd_pkt_devp->i);
/* notify client that a reset occurred */
@@ -485,6 +492,9 @@
__func__, smd_pkt_devp->i);
return notify_reset(smd_pkt_devp);
}
+ pr_err("%s on smd_pkt_dev id:%d failed r:%d\n",
+ __func__, smd_pkt_devp->i, r);
+ return r;
}
bytes_written += r;
}
@@ -512,11 +522,20 @@
smd_pkt_devp->poll_mode = 1;
poll_wait(file, &smd_pkt_devp->ch_read_wait_queue, wait);
+ mutex_lock(&smd_pkt_devp->ch_lock);
+ if (smd_pkt_devp->has_reset || !smd_pkt_devp->ch) {
+ mutex_unlock(&smd_pkt_devp->ch_lock);
+ pr_err("%s notifying reset for smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
+ return POLLERR;
+ }
+
if (smd_read_avail(smd_pkt_devp->ch)) {
mask |= POLLIN | POLLRDNORM;
D_POLL("%s sets POLLIN for smd_pkt_dev id: %d\n",
__func__, smd_pkt_devp->i);
}
+ mutex_unlock(&smd_pkt_devp->ch_lock);
return mask;
}
@@ -814,8 +833,12 @@
r = wait_event_interruptible_timeout(
smd_pkt_devp->ch_opened_wait_queue,
smd_pkt_devp->is_open, (2 * HZ));
- if (r == 0)
+ if (r == 0) {
r = -ETIMEDOUT;
+ /* close the ch to sync smd's state with smd_pkt */
+ smd_close(smd_pkt_devp->ch);
+ smd_pkt_devp->ch = NULL;
+ }
if (r < 0) {
pr_err("%s: wait on smd_pkt_dev id:%d OPEN event failed"
@@ -864,6 +887,8 @@
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) {
r = smd_close(smd_pkt_devp->ch);
smd_pkt_devp->ch = 0;
@@ -873,6 +898,8 @@
if (smd_pkt_devp->pil)
pil_put(smd_pkt_devp->pil);
}
+ 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;
diff --git a/arch/arm/mach-msm/sysmon.c b/arch/arm/mach-msm/sysmon.c
index ddb8502..679393d 100644
--- a/arch/arm/mach-msm/sysmon.c
+++ b/arch/arm/mach-msm/sysmon.c
@@ -111,10 +111,10 @@
mutex_lock(&ss->lock);
switch (ss->transport) {
case TRANSPORT_SMD:
- ret = sysmon_send_smd(ss, tx_buf, ARRAY_SIZE(tx_buf));
+ ret = sysmon_send_smd(ss, tx_buf, strlen(tx_buf));
break;
case TRANSPORT_HSIC:
- ret = sysmon_send_hsic(ss, tx_buf, ARRAY_SIZE(tx_buf));
+ ret = sysmon_send_hsic(ss, tx_buf, strlen(tx_buf));
break;
default:
ret = -EINVAL;
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 2e422c4..f643dca 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -323,11 +323,11 @@
#endif
#ifndef CONFIG_SPARSEMEM
-static void arm_memory_present(void)
+static void __init arm_memory_present(void)
{
}
#else
-static void arm_memory_present(void)
+static void __init arm_memory_present(void)
{
struct meminfo *mi = &meminfo;
int i;
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index a31afb8..c841d87 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -614,8 +614,8 @@
}
}
-static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
- unsigned long phys, const struct mem_type *type)
+static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
+ unsigned long end, unsigned long phys, const struct mem_type *type)
{
pud_t *pud = pud_offset(pgd, addr);
unsigned long next;
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 6fa053b..050fd83 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1325,7 +1325,7 @@
{
int result;
- calc_gmemsize(&drawctxt->context_gmem_shadow, adreno_dev->gmem_base);
+ calc_gmemsize(&drawctxt->context_gmem_shadow, adreno_dev->gmem_size);
tmp_ctx.gmem_base = adreno_dev->gmem_base;
result = kgsl_allocate(&drawctxt->context_gmem_shadow.gmemshadow,
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index a992059..fe01764 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -464,8 +464,11 @@
if (context) {
total_sizedwords += 3; /* sop timestamp */
total_sizedwords += 4; /* eop timestamp */
+ total_sizedwords += 3; /* global timestamp without cache
+ * flush for non-zero context */
+ } else {
+ total_sizedwords += 4; /* global timestamp for recovery*/
}
- total_sizedwords += 4; /* global timestamp for recovery*/
ringcmds = adreno_ringbuffer_allocspace(rb, total_sizedwords);
rcmd_gpu = rb->buffer_desc.gpuaddr
@@ -538,14 +541,24 @@
GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
KGSL_MEMSTORE_OFFSET(context->id, eoptimestamp)));
GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
- }
- GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type3_packet(CP_EVENT_WRITE, 3));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
- GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
- KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
- eoptimestamp)));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
+ GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ cp_type3_packet(CP_MEM_WRITE, 2));
+ GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ eoptimestamp)));
+ GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
+ } else {
+ GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ cp_type3_packet(CP_EVENT_WRITE, 3));
+ GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
+ GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ eoptimestamp)));
+ GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
+ }
if (!(flags & KGSL_CMD_FLAGS_NO_TS_CMP)) {
/* Conditional execution based on memory values */
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index d050599..37a1ff2 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -791,6 +791,9 @@
(struct msm_camera_sensor_info *) s_ctrl->sensordata;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+ v4l2_subdev_call(p_mctl->sensor_sdev, core, ioctl,
+ VIDIOC_MSM_SENSOR_RELEASE, NULL);
+
if (camdev->is_ispif) {
v4l2_subdev_call(p_mctl->ispif_sdev, core, ioctl,
VIDIOC_MSM_ISPIF_RELEASE, NULL);
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index e0fa962..cc56ccf 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -368,6 +368,24 @@
return rc;
}
+int32_t msm_sensor_release(struct msm_sensor_ctrl_t *s_ctrl)
+{
+ long fps = 0;
+ uint32_t delay = 0;
+ CDBG("%s called\n", __func__);
+ s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
+ if (s_ctrl->curr_res != MSM_SENSOR_INVALID_RES) {
+ fps = s_ctrl->msm_sensor_reg->
+ output_settings[s_ctrl->curr_res].vt_pixel_clk /
+ s_ctrl->curr_frame_length_lines /
+ s_ctrl->curr_line_length_pclk;
+ delay = 1000 / fps;
+ CDBG("%s fps = %ld, delay = %d\n", __func__, fps, delay);
+ msleep(delay);
+ }
+ return 0;
+}
+
long msm_sensor_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg)
{
@@ -376,6 +394,8 @@
switch (cmd) {
case VIDIOC_MSM_SENSOR_CFG:
return s_ctrl->func_tbl->sensor_config(s_ctrl, argp);
+ case VIDIOC_MSM_SENSOR_RELEASE:
+ return msm_sensor_release(s_ctrl);
default:
return -ENOIOCTLCMD;
}
diff --git a/drivers/media/video/msm/sensors/msm_sensor.h b/drivers/media/video/msm/sensors/msm_sensor.h
index 421e1d1..0104b98 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -249,4 +249,7 @@
#define VIDIOC_MSM_SENSOR_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE + 10, void __user *)
+#define VIDIOC_MSM_SENSOR_RELEASE \
+ _IO('V', BASE_VIDIOC_PRIVATE + 11)
+
#endif
diff --git a/drivers/media/video/msm/sensors/ov5647_v4l2.c b/drivers/media/video/msm/sensors/ov5647_v4l2.c
index 7c23fe6..ca2bb98 100644
--- a/drivers/media/video/msm/sensors/ov5647_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov5647_v4l2.c
@@ -449,7 +449,7 @@
gain_lsb = (uint8_t) (gain);
gain_hsb = (uint8_t)((gain & 0x300)>>8);
/* adjust frame rate */
- if (line > 980) {
+ if (line > 980 && line <= 984) {
msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
s_ctrl->sensor_output_reg_addr->frame_length_lines,
diff --git a/drivers/media/video/msm/wfd/enc-subdev.c b/drivers/media/video/msm/wfd/enc-subdev.c
index 95cdc59..e9c710a 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.c
+++ b/drivers/media/video/msm/wfd/enc-subdev.c
@@ -603,6 +603,7 @@
struct vcd_property_profile vcd_property_profile;
struct vcd_property_hdr vcd_property_hdr;
struct vcd_property_codec vcd_property_codec;
+ struct vcd_property_i_period vcd_property_i_period;
int rc = 0;
/* Validate params */
@@ -614,7 +615,7 @@
if (rc < 0) {
WFD_MSG_ERR("Error getting codec property");
rc = -EINVAL;
- goto err;
+ goto err_set_profile;
}
if (!((vcd_property_codec.codec == VCD_CODEC_H264
@@ -624,7 +625,7 @@
WFD_MSG_ERR("Attempting to set %d for codec type %d",
codec, vcd_property_codec.codec);
rc = -EINVAL;
- goto err;
+ goto err_set_profile;
}
/* Set property */
@@ -671,12 +672,31 @@
"not setting profile (%d)",
codec, profile);
rc = -ENOTSUPP;
- goto err;
+ goto err_set_profile;
}
rc = vcd_set_property(client_ctx->vcd_handle,
&vcd_property_hdr, &vcd_property_profile);
-err:
+
+ /* Disable B-frames, since VSG doesn't support out of order i/p bufs */
+ vcd_property_hdr.prop_id = VCD_I_INTRA_PERIOD;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_i_period);
+
+ rc = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_property_i_period);
+ if (rc) {
+ WFD_MSG_ERR("Error getting I-period property");
+ goto err_set_profile;
+ }
+ vcd_property_i_period.b_frames = 0;
+ rc = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_property_i_period);
+ if (rc) {
+ WFD_MSG_ERR("Error setting I-period property");
+ goto err_set_profile;
+ }
+
+err_set_profile:
return rc;
}
@@ -1610,6 +1630,65 @@
return rc;
}
+static long venc_set_cyclic_intra_refresh_mb(
+ struct video_client_ctx *client_ctx,
+ __s32 value)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_intra_refresh_mb_number cir_mb_num;
+ int rc = 0;
+
+ if (!client_ctx) {
+ WFD_MSG_ERR("Invalid parameters\n");
+ rc = -EINVAL;
+ goto set_cir_mbs_fail;
+ }
+
+ vcd_property_hdr.prop_id = VCD_I_INTRA_REFRESH;
+ vcd_property_hdr.sz = sizeof(cir_mb_num);
+
+ cir_mb_num.cir_mb_number = value;
+
+ rc = vcd_set_property(client_ctx->vcd_handle, &vcd_property_hdr,
+ &cir_mb_num);
+ if (rc) {
+ WFD_MSG_ERR("Failed to set CIR MBs\n");
+ goto set_cir_mbs_fail;
+ }
+
+set_cir_mbs_fail:
+ return rc;
+}
+
+static long venc_get_cyclic_intra_refresh_mb(
+ struct video_client_ctx *client_ctx,
+ __s32 *value)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_intra_refresh_mb_number cir_mb_num;
+ int rc = 0;
+
+ if (!client_ctx || !value) {
+ WFD_MSG_ERR("Invalid parameters\n");
+ rc = -EINVAL;
+ goto get_cir_mbs_fail;
+ }
+
+ vcd_property_hdr.prop_id = VCD_I_INTRA_REFRESH;
+ vcd_property_hdr.sz = sizeof(cir_mb_num);
+
+ rc = vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+ &cir_mb_num);
+ if (rc) {
+ WFD_MSG_ERR("Failed to set CIR MBs\n");
+ goto get_cir_mbs_fail;
+ }
+
+ *value = cir_mb_num.cir_mb_number;
+
+get_cir_mbs_fail:
+ return rc;
+}
static long venc_set_input_buffer(struct v4l2_subdev *sd, void *arg)
{
struct mem_region *mregion = arg;
@@ -1988,6 +2067,9 @@
case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
rc = venc_set_entropy_mode(client_ctx, ctrl->value);
break;
+ case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
+ rc = venc_set_cyclic_intra_refresh_mb(client_ctx, ctrl->value);
+ break;
default:
WFD_MSG_ERR("Set property not suported: %d\n", ctrl->id);
rc = -ENOTSUPP;
@@ -2050,6 +2132,9 @@
case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
rc = venc_get_entropy_mode(client_ctx, &ctrl->value);
break;
+ case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
+ rc = venc_get_cyclic_intra_refresh_mb(client_ctx, &ctrl->value);
+ break;
default:
WFD_MSG_ERR("Get property not suported: %d\n", ctrl->id);
rc = -ENOTSUPP;
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index 3b7bdc8..3aff7f17 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -141,7 +141,7 @@
struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
u16 slave_port_id = 0;
- pr_err("%s: pgd_la[%d]\n", __func__, wcd9xxx_pgd_la);
+ pr_debug("%s: pgd_la[%d]\n", __func__, wcd9xxx_pgd_la);
/* DSP requires channel number to be between 128 and 255. For RX port
* use channel numbers from 138 to 144, for TX port
* use channel numbers from 128 to 137
@@ -218,7 +218,7 @@
struct slim_ch prop;
/* Configure slave interface device */
- pr_err("%s: ch_cnt[%d] rate=%d\n", __func__, ch_cnt, rate);
+ pr_debug("%s: ch_cnt[%d] rate=%d\n", __func__, ch_cnt, rate);
for (i = 0; i < ch_cnt; i++) {
idx = (ch_num[i] - BASE_CH_NUM -
@@ -458,7 +458,7 @@
int ret = 0;
struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
- pr_err("%s: ch_cnt[%d]\n", __func__, ch_cnt);
+ pr_debug("%s: ch_cnt[%d]\n", __func__, ch_cnt);
for (i = 0; i < ch_cnt; i++) {
idx = (ch_num[i] - BASE_CH_NUM -
SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
@@ -498,7 +498,7 @@
int i = 0 , idx = 0;
struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
- pr_err("%s: ch_cnt[%d]\n", __func__, ch_cnt);
+ pr_debug("%s: ch_cnt[%d]\n", __func__, ch_cnt);
for (i = 0; i < ch_cnt; i++) {
idx = (ch_num[i] - BASE_CH_NUM);
sph[i] = tx[idx].sph;
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 5dbf839..44228a6 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1625,6 +1625,11 @@
MMC_QUIRK_BLK_NO_CMD23),
MMC_FIXUP("MMC32G", 0x11, CID_OEMID_ANY, add_quirk_mmc,
MMC_QUIRK_BLK_NO_CMD23),
+
+ /* Some INAND MCP devices advertise incorrect timeout values */
+ MMC_FIXUP("SEM04G", 0x45, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_INAND_DATA_TIMEOUT),
+
END_FIXUP
};
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index ca86323..843a707 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -523,6 +523,11 @@
data->timeout_ns = 100000000; /* 100ms */
}
}
+ /* Increase the timeout values for some bad INAND MCP devices */
+ if (card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT) {
+ data->timeout_ns = 4000000000u; /* 4s */
+ data->timeout_clks = 0;
+ }
}
EXPORT_SYMBOL(mmc_set_data_timeout);
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index aa1a589..b0439bc 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -132,6 +132,10 @@
unsigned int rconn_mohm;
struct mutex last_ocv_uv_mutex;
int last_ocv_uv;
+ int last_cc_uah; /* used for Iavg calc for UUC */
+ struct timeval t;
+ int last_uuc_uah;
+ int enable_fcc_learning;
};
static struct pm8921_bms_chip *the_chip;
@@ -966,6 +970,8 @@
convert_vbatt_raw_to_uv(chip, usb_chg,
raw->last_good_ocv_raw, &raw->last_good_ocv_uv);
chip->last_ocv_uv = raw->last_good_ocv_uv;
+ /* forget the old cc value upon ocv */
+ chip->last_cc_uah = 0;
} else {
raw->last_good_ocv_uv = chip->last_ocv_uv;
}
@@ -1147,20 +1153,128 @@
*val = cc_uah;
}
-static int calculate_unusable_charge_uah(struct pm8921_bms_chip *chip,
- int rbatt, int fcc_uah,
- int batt_temp, int chargecycles)
+static int calculate_uuc_uah_at_given_current(struct pm8921_bms_chip *chip,
+ int batt_temp, int chargecycles,
+ int rbatt, int fcc_uah, int i_ma)
{
- int voltage_unusable_uv, pc_unusable;
+ int unusable_uv, pc_unusable, uuc;
- /* calculate unusable charge */
- voltage_unusable_uv = (rbatt * chip->i_test)
- + (chip->v_failure * 1000);
- pc_unusable = calculate_pc(chip, voltage_unusable_uv,
- batt_temp, chargecycles);
- pr_debug("rbatt = %umilliOhms unusable_v =%d unusable_pc = %d\n",
- rbatt, voltage_unusable_uv, pc_unusable);
- return (fcc_uah * pc_unusable) / 100;
+ /* calculate unusable charge with itest */
+ unusable_uv = (rbatt * i_ma) + (chip->v_failure * 1000);
+ pc_unusable = calculate_pc(chip, unusable_uv, batt_temp, chargecycles);
+ uuc = (fcc_uah * pc_unusable) / 100;
+ pr_debug("For i_ma = %d, unusable_uv = %d unusable_pc = %d uuc = %d\n",
+ i_ma, unusable_uv, pc_unusable, uuc);
+ return uuc;
+}
+
+/* soc_rbatt when uuc_reported should be equal to uuc_now */
+#define SOC_RBATT_CHG 80
+#define SOC_RBATT_DISCHG 10
+static int calculate_unusable_charge_uah(struct pm8921_bms_chip *chip,
+ int rbatt, int fcc_uah, int cc_uah,
+ int soc_rbatt, int batt_temp, int chargecycles)
+{
+ struct timeval now;
+ int delta_time_s;
+ int delta_cc_uah;
+ int iavg_ua, iavg_ma;
+ int uuc_uah_itest, uuc_uah_iavg, uuc_now, uuc_reported;
+ s64 stepsize = 0;
+ int firsttime = 0;
+
+ delta_cc_uah = cc_uah - chip->last_cc_uah;
+ do_gettimeofday(&now);
+ if (chip->t.tv_sec != 0) {
+ delta_time_s = (now.tv_sec - chip->t.tv_sec);
+ } else {
+ /* uuc calculation for the first time */
+ delta_time_s = 0;
+ firsttime = 1;
+ }
+
+ if (delta_time_s != 0)
+ iavg_ua = div_s64((s64)delta_cc_uah * 3600, delta_time_s);
+ else
+ iavg_ua = 0;
+
+ iavg_ma = iavg_ua/1000;
+
+ pr_debug("t.tv_sec = %d, now.tv_sec = %d\n", (int)chip->t.tv_sec,
+ (int)now.tv_sec);
+
+ pr_debug("delta_time_s = %d iavg_ma = %d\n", delta_time_s, iavg_ma);
+
+ if (iavg_ma == 0) {
+ pr_debug("Iavg = 0 returning last uuc = %d\n",
+ chip->last_uuc_uah);
+ uuc_reported = chip->last_uuc_uah;
+ goto out;
+ }
+
+ /* calculate unusable charge with itest */
+ uuc_uah_itest = calculate_uuc_uah_at_given_current(chip,
+ batt_temp, chargecycles,
+ rbatt, fcc_uah, chip->i_test);
+
+ pr_debug("itest = %d uuc_itest = %d\n", chip->i_test, uuc_uah_itest);
+
+ /* calculate unusable charge with iavg */
+ iavg_ma = max(0, iavg_ma);
+ uuc_uah_iavg = calculate_uuc_uah_at_given_current(chip,
+ batt_temp, chargecycles,
+ rbatt, fcc_uah, iavg_ma);
+ pr_debug("iavg = %d uuc_iavg = %d\n", iavg_ma, uuc_uah_iavg);
+
+ if (firsttime) {
+ if (cc_uah < chip->last_cc_uah)
+ chip->last_uuc_uah = uuc_uah_itest;
+ else
+ chip->last_uuc_uah = uuc_uah_iavg;
+ pr_debug("firsttime uuc_prev = %d\n", chip->last_uuc_uah);
+ }
+
+ uuc_now = min(uuc_uah_itest, uuc_uah_iavg);
+
+ uuc_reported = -EINVAL;
+ if (cc_uah < chip->last_cc_uah) {
+ /* charging */
+ if (uuc_now < chip->last_uuc_uah) {
+ stepsize = max(1, (SOC_RBATT_CHG - soc_rbatt));
+ /* uuc_reported = uuc_prev + deltauuc / stepsize */
+ uuc_reported = div_s64 (stepsize * chip->last_uuc_uah
+ + (uuc_now - chip->last_uuc_uah),
+ stepsize);
+ uuc_reported = max(0, uuc_reported);
+ }
+ } else {
+ if (uuc_now > chip->last_uuc_uah) {
+ stepsize = max(1, (soc_rbatt - SOC_RBATT_DISCHG));
+ /* uuc_reported = uuc_prev + deltauuc / stepsize */
+ uuc_reported = div_s64 (stepsize * chip->last_uuc_uah
+ + (uuc_now - chip->last_uuc_uah),
+ stepsize);
+ uuc_reported = max(0, uuc_reported);
+ }
+ }
+ if (uuc_reported == -EINVAL)
+ uuc_reported = chip->last_uuc_uah;
+
+ pr_debug("uuc_now = %d uuc_prev = %d stepsize = %d uuc_reported = %d\n",
+ uuc_now, chip->last_uuc_uah, (int)stepsize,
+ uuc_reported);
+
+out:
+ /* remember the reported uuc */
+ chip->last_uuc_uah = uuc_reported;
+
+ /* remember cc_uah */
+ chip->last_cc_uah = cc_uah;
+
+ /* remember this time */
+ chip->t = now;
+
+ return uuc_reported;
}
/* calculate remainging charge at the time of ocv */
@@ -1211,7 +1325,9 @@
*rbatt = get_rbatt(chip, soc_rbatt, batt_temp);
*unusable_charge_uah = calculate_unusable_charge_uah(chip, *rbatt,
- *fcc_uah, batt_temp, chargecycles);
+ *fcc_uah, *cc_uah, soc_rbatt,
+ batt_temp,
+ chargecycles);
pr_debug("UUC = %uuAh\n", *unusable_charge_uah);
}
@@ -1644,6 +1760,8 @@
#define OCV_TOL_MASK 0xF0
#define IBAT_TOL_DEFAULT 0x03
#define IBAT_TOL_NOCHG 0x0F
+#define OCV_TOL_DEFAULT 0x20
+#define OCV_TOL_NO_OCV 0x00
void pm8921_bms_charging_began(void)
{
int batt_temp, rc;
@@ -1705,7 +1823,7 @@
bms_end_ocv_uv = raw.last_good_ocv_uv;
- if (is_battery_full
+ if (is_battery_full && the_chip->enable_fcc_learning
&& the_chip->start_percent <= MIN_START_PERCENT_FOR_LEARNING) {
int fcc_uah, new_fcc_uah, delta_fcc_uah;
@@ -1745,6 +1863,11 @@
the_chip->last_ocv_uv = the_chip->max_voltage_uv;
raw.last_good_ocv_uv = the_chip->max_voltage_uv;
+ /*
+ * since we are treating this as an ocv event
+ * forget the old cc value
+ */
+ the_chip->last_cc_uah = 0;
pr_debug("EOC ocv_reading = 0x%x cc = 0x%x\n",
the_chip->ocv_reading_at_100,
the_chip->cc_reading_at_100);
@@ -1776,6 +1899,22 @@
}
EXPORT_SYMBOL_GPL(pm8921_bms_charging_end);
+int pm8921_bms_stop_ocv_updates(struct pm8921_bms_chip *chip)
+{
+ pr_debug("stopping ocv updates\n");
+ return pm_bms_masked_write(chip, BMS_TOLERANCES,
+ OCV_TOL_MASK, OCV_TOL_NO_OCV);
+}
+EXPORT_SYMBOL_GPL(pm8921_bms_stop_ocv_updates);
+
+int pm8921_bms_start_ocv_updates(struct pm8921_bms_chip *chip)
+{
+ pr_debug("stopping ocv updates\n");
+ return pm_bms_masked_write(chip, BMS_TOLERANCES,
+ OCV_TOL_MASK, OCV_TOL_DEFAULT);
+}
+EXPORT_SYMBOL_GPL(pm8921_bms_start_ocv_updates);
+
static irqreturn_t pm8921_bms_sbi_write_ok_handler(int irq, void *data)
{
pr_debug("irq = %d triggered", irq);
@@ -2110,6 +2249,8 @@
CALIB_HKADC,
CALIB_CCADC,
GET_VBAT_VSENSE_SIMULTANEOUS,
+ STOP_OCV,
+ START_OCV,
};
static int test_batt_temp = 5;
@@ -2202,13 +2343,30 @@
pm8921_bms_get_simultaneous_battery_voltage_and_current(
&ibat_ua,
&vbat_uv);
+ default:
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static int set_calc(void *data, u64 val)
+{
+ int param = (int)data;
+ int ret = 0;
+
+ switch (param) {
+ case STOP_OCV:
+ pm8921_bms_stop_ocv_updates(the_chip);
+ break;
+ case START_OCV:
+ pm8921_bms_start_ocv_updates(the_chip);
break;
default:
ret = -EINVAL;
}
return ret;
}
-DEFINE_SIMPLE_ATTRIBUTE(calc_fops, get_calc, NULL, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(calc_fops, get_calc, set_calc, "%llu\n");
static int get_reading(void *data, u64 * val)
{
@@ -2346,6 +2504,10 @@
(void *)CALIB_HKADC, &calc_fops);
debugfs_create_file("calib_ccadc", 0644, chip->dent,
(void *)CALIB_CCADC, &calc_fops);
+ debugfs_create_file("stop_ocv", 0644, chip->dent,
+ (void *)STOP_OCV, &calc_fops);
+ debugfs_create_file("start_ocv", 0644, chip->dent,
+ (void *)START_OCV, &calc_fops);
debugfs_create_file("simultaneous", 0644, chip->dent,
(void *)GET_VBAT_VSENSE_SIMULTANEOUS, &calc_fops);
@@ -2467,6 +2629,7 @@
chip->ref1p25v_channel = pdata->bms_cdata.ref1p25v_channel;
chip->batt_id_channel = pdata->bms_cdata.batt_id_channel;
chip->revision = pm8xxx_get_revision(chip->dev->parent);
+ chip->enable_fcc_learning = pdata->enable_fcc_learning;
INIT_WORK(&chip->calib_hkadc_work, calibrate_hkadc_work);
rc = request_irqs(chip, pdev);
diff --git a/drivers/usb/gadget/ci13xxx_msm_hsic.c b/drivers/usb/gadget/ci13xxx_msm_hsic.c
index c74b69a..eeacceb 100644
--- a/drivers/usb/gadget/ci13xxx_msm_hsic.c
+++ b/drivers/usb/gadget/ci13xxx_msm_hsic.c
@@ -283,6 +283,12 @@
return 0;
}
+static void msm_hsic_wakeup(void)
+{
+ if (atomic_read(&the_mhsic->in_lpm))
+ pm_runtime_resume(the_mhsic->dev);
+}
+
static void msm_hsic_start(void)
{
int ret;
@@ -580,6 +586,10 @@
dev_dbg(dev, "CI13XXX_CONTROLLER_SUSPEND_EVENT received\n");
queue_work(mhsic->wq, &mhsic->suspend_w);
break;
+ case CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT:
+ dev_dbg(dev, "CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT received\n");
+ msm_hsic_wakeup();
+ break;
default:
dev_dbg(dev, "unknown ci13xxx_udc event\n");
break;
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 54d041a..d754a88 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -1476,6 +1476,15 @@
dbg_trace("remote wakeup feature is not enabled\n");
goto out;
}
+ spin_unlock_irqrestore(udc->lock, flags);
+
+ udc->udc_driver->notify_event(udc,
+ CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT);
+
+ if (udc->transceiver)
+ otg_set_suspend(udc->transceiver, 0);
+
+ spin_lock_irqsave(udc->lock, flags);
if (!hw_cread(CAP_PORTSC, PORTSC_SUSP)) {
ret = -EINVAL;
dbg_trace("port is not suspended\n");
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index 0c811e1..8e2b093 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -120,9 +120,10 @@
#define CI13XXX_ZERO_ITC BIT(4)
#define CI13XXX_IS_OTG BIT(5)
-#define CI13XXX_CONTROLLER_RESET_EVENT 0
-#define CI13XXX_CONTROLLER_CONNECT_EVENT 1
-#define CI13XXX_CONTROLLER_SUSPEND_EVENT 2
+#define CI13XXX_CONTROLLER_RESET_EVENT 0
+#define CI13XXX_CONTROLLER_CONNECT_EVENT 1
+#define CI13XXX_CONTROLLER_SUSPEND_EVENT 2
+#define CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT 3
void (*notify_event) (struct ci13xxx *udc, unsigned event);
};
diff --git a/drivers/usb/gadget/f_accessory.c b/drivers/usb/gadget/f_accessory.c
index 0187b69..9f14b09 100644
--- a/drivers/usb/gadget/f_accessory.c
+++ b/drivers/usb/gadget/f_accessory.c
@@ -296,7 +296,7 @@
}
}
-static int __init create_bulk_endpoints(struct acc_dev *dev,
+static int create_bulk_endpoints(struct acc_dev *dev,
struct usb_endpoint_descriptor *in_desc,
struct usb_endpoint_descriptor *out_desc)
{
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index 4dc3c80..537e0b5 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -118,6 +118,8 @@
* calculated or the peak system current (mA)
* @v_failure: the voltage at which the battery is considered empty(mV)
* @calib_delay_ms: how often should the adc calculate gain and offset
+ * @enable_fcc_learning: if set the driver will learn full charge
+ * capacity of the battery upon end of charge
*/
struct pm8921_bms_platform_data {
struct pm8xxx_bms_core_data bms_cdata;
@@ -128,6 +130,7 @@
unsigned int calib_delay_ms;
unsigned int max_voltage_uv;
unsigned int rconn_mohm;
+ int enable_fcc_learning;
};
#if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 0fcae7c..8a0c4d5 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -202,6 +202,7 @@
#define MMC_QUIRK_DISABLE_CD (1<<5) /* disconnect CD/DAT[3] resistor */
#define MMC_QUIRK_INAND_CMD38 (1<<6) /* iNAND devices have broken CMD38 */
#define MMC_QUIRK_BLK_NO_CMD23 (1<<7) /* Avoid CMD23 for regular multiblock */
+#define MMC_QUIRK_INAND_DATA_TIMEOUT (1<<8) /* For incorrect data timeout */
unsigned int poweroff_notify_state; /* eMMC4.5 notify feature */
#define MMC_NO_POWER_NOTIFICATION 0
#define MMC_POWERED_ON 1
diff --git a/include/sound/soc.h b/include/sound/soc.h
index f51b006..12a8fd5 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -814,6 +814,7 @@
struct list_head list;
struct mutex mutex;
struct mutex dapm_mutex;
+ struct mutex dapm_power_mutex;
struct mutex dsp_mutex;
spinlock_t dsp_spinlock;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 8c07206..95c6b1d 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1530,7 +1530,7 @@
if (PCM_RUNTIME_CHECK(substream))
return -ENXIO;
runtime = substream->runtime;
- pr_err("%s called with cmd = %d\n", __func__, cmd);
+ pr_debug("%s called with cmd = %d\n", __func__, cmd);
err = substream->ops->ioctl(substream, cmd, arg);
return err;
}
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index 961f833..ea05a58e 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -57,6 +57,14 @@
#define GPIO_SEC_I2S_RX_MCLK 50
#define I2S_MCLK_RATE 1536000
+#define GPIO_MI2S_WS 27
+#define GPIO_MI2S_SCLK 28
+#define GPIO_MI2S_DOUT3 29
+#define GPIO_MI2S_DOUT2 30
+#define GPIO_MI2S_DOUT1 31
+#define GPIO_MI2S_DOUT0 32
+#define GPIO_MI2S_MCLK 33
+
static struct clk *sec_i2s_rx_osr_clk;
static struct clk *sec_i2s_rx_bit_clk;
@@ -84,6 +92,41 @@
},
};
+static struct request_gpio mi2s_gpio[] = {
+ {
+ .gpio_no = GPIO_MI2S_WS,
+ .gpio_name = "MI2S_WS",
+ },
+ {
+ .gpio_no = GPIO_MI2S_SCLK,
+ .gpio_name = "MI2S_SCLK",
+ },
+ {
+ .gpio_no = GPIO_MI2S_DOUT3,
+ .gpio_name = "MI2S_DOUT3",
+ },
+ {
+ .gpio_no = GPIO_MI2S_DOUT2,
+ .gpio_name = "MI2S_DOUT2",
+ },
+ {
+ .gpio_no = GPIO_MI2S_DOUT1,
+ .gpio_name = "MI2S_DOUT1",
+ },
+ {
+ .gpio_no = GPIO_MI2S_DOUT0,
+ .gpio_name = "MI2S_DOUT0",
+ },
+ {
+ .gpio_no = GPIO_MI2S_MCLK,
+ .gpio_name = "MI2S_MCLK",
+ },
+};
+
+static struct clk *mi2s_bit_clk;
+
+
+
static u32 top_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(18);
static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
static int msm_spk_control;
@@ -736,7 +779,7 @@
},
};
-static struct snd_soc_dsp_link slimbus0_hl_media = {
+static struct snd_soc_dsp_link bidir_hl_media = {
.playback = true,
.capture = true,
.trigger = {
@@ -745,8 +788,7 @@
},
};
-static struct snd_soc_dsp_link int_fm_hl_media = {
- .playback = true,
+static struct snd_soc_dsp_link tx_hl_media = {
.capture = true,
.trigger = {
SND_SOC_DSP_TRIGGER_POST,
@@ -754,6 +796,14 @@
},
};
+
+static struct snd_soc_dsp_link rx_hl_media = {
+ .playback = true,
+ .trigger = {
+ SND_SOC_DSP_TRIGGER_POST,
+ SND_SOC_DSP_TRIGGER_POST
+ },
+};
static int msm_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -815,6 +865,71 @@
return 0;
}
+static int msm_mi2s_free_gpios(void)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(mi2s_gpio); i++)
+ gpio_free(mi2s_gpio[i].gpio_no);
+ return 0;
+}
+
+static void msm_mi2s_shutdown(struct snd_pcm_substream *substream)
+{
+ if (mi2s_bit_clk) {
+ clk_disable(mi2s_bit_clk);
+ clk_put(mi2s_bit_clk);
+ mi2s_bit_clk = NULL;
+ }
+ msm_mi2s_free_gpios();
+}
+
+static int configure_mi2s_gpio(void)
+{
+ int rtn;
+ int i;
+ int j;
+ for (i = 0; i < ARRAY_SIZE(mi2s_gpio); i++) {
+ rtn = gpio_request(mi2s_gpio[i].gpio_no,
+ mi2s_gpio[i].gpio_name);
+ pr_debug("%s: gpio = %d, gpio name = %s, rtn = %d\n",
+ __func__,
+ mi2s_gpio[i].gpio_no,
+ mi2s_gpio[i].gpio_name,
+ rtn);
+ if (rtn) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__,
+ mi2s_gpio[i].gpio_no);
+ for (j = i; j >= 0; j--)
+ gpio_free(mi2s_gpio[j].gpio_no);
+ goto err;
+ }
+ }
+err:
+ return rtn;
+}
+static int msm_mi2s_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ configure_mi2s_gpio();
+ mi2s_bit_clk = clk_get(cpu_dai->dev, "bit_clk");
+ if (IS_ERR(mi2s_bit_clk))
+ return PTR_ERR(mi2s_bit_clk);
+ clk_set_rate(mi2s_bit_clk, 0);
+ ret = clk_enable(mi2s_bit_clk);
+ if (IS_ERR_VALUE(ret)) {
+ pr_err("Unable to enable mi2s_bit_clk\n");
+ clk_put(mi2s_bit_clk);
+ return ret;
+ }
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM);
+ if (IS_ERR_VALUE(ret))
+ pr_err("set format for CPU dai failed\n");
+ return ret;
+}
+
static int msm_startup(struct snd_pcm_substream *substream)
{
pr_debug("%s(): substream = %s stream = %d\n", __func__,
@@ -958,6 +1073,12 @@
.hw_params = mpq8064_sec_i2s_rx_hw_params,
};
+static struct snd_soc_ops msm_mi2s_tx_be_ops = {
+ .startup = msm_mi2s_startup,
+ .shutdown = msm_mi2s_shutdown,
+};
+
+
/* Digital audio interface glue - connects codec <---> CPU */
static struct snd_soc_dai_link msm_dai[] = {
/* FrontEnd DAI Links */
@@ -1015,7 +1136,7 @@
.cpu_dai_name = "SLIMBUS0_HOSTLESS",
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
- .dsp_link = &slimbus0_hl_media,
+ .dsp_link = &bidir_hl_media,
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
/* .be_id = do not care */
@@ -1026,7 +1147,7 @@
.cpu_dai_name = "INT_FM_HOSTLESS",
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
- .dsp_link = &int_fm_hl_media,
+ .dsp_link = &bidir_hl_media,
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
/* .be_id = do not care */
@@ -1064,11 +1185,47 @@
.cpu_dai_name = "VOICE_STUB",
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
- .dsp_link = &fe_media,
+ .dsp_link = &bidir_hl_media,
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
/* .be_id = do not care */
},
+ /* MI2S TX Hostless */
+ {
+ .name = "MI2S_TX Hostless",
+ .stream_name = "MI2S_TX Hostless",
+ .cpu_dai_name = "MI2S_TX_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dsp_link = &tx_hl_media,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .no_codec = 1,
+ .ignore_suspend = 1,
+ },
+ /* HDMI Hostless */
+ {
+ .name = "HDMI_RX_HOSTLESS",
+ .stream_name = "HDMI_RX_HOSTLESS",
+ .cpu_dai_name = "HDMI_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dsp_link = &rx_hl_media,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .no_codec = 1,
+ .ignore_suspend = 1,
+ },
+ /* Secondary I2S RX Hostless */
+ {
+ .name = "SEC_I2S_RX Hostless",
+ .stream_name = "SEC_I2S_RX Hostless",
+ .cpu_dai_name = "SEC_I2S_RX_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dsp_link = &rx_hl_media,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .no_codec = 1,
+ .ignore_suspend = 1,
+ },
/* Backend DAI Links */
{
.name = LPASS_BE_SLIMBUS_0_RX,
@@ -1142,6 +1299,19 @@
.be_id = MSM_BACKEND_DAI_HDMI_RX,
.be_hw_params_fixup = msm_hdmi_be_hw_params_fixup,
},
+ {
+ .name = LPASS_BE_MI2S_TX,
+ .stream_name = "MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6.7",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .no_codec = 1,
+ .be_id = MSM_BACKEND_DAI_MI2S_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_mi2s_tx_be_ops,
+ },
/* Backend AFE DAI Links */
{
.name = LPASS_BE_AFE_PCM_RX,
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index b3fb7c1..cb760fa 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -29,6 +29,7 @@
#include <asm/dma.h>
#include <linux/dma-mapping.h>
#include <linux/android_pmem.h>
+#include <sound/timer.h>
#include "msm-compr-q6.h"
#include "msm-pcm-routing.h"
@@ -92,6 +93,9 @@
prtd->pcm_irq_pos += prtd->pcm_count;
if (atomic_read(&prtd->start))
snd_pcm_period_elapsed(substream);
+ else
+ if (substream->timer_running)
+ snd_timer_interrupt(substream->timer, 1);
atomic_inc(&prtd->out_count);
wake_up(&the_locks.write_wait);
if (!atomic_read(&prtd->start)) {
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 3f86962..23134ea 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -315,6 +315,32 @@
.ops = &msm_fe_dai_ops,
.name = "VoLTE",
},
+ {
+ .capture = {
+ .stream_name = "MI2S_TX Hostless Capture",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "MI2S_TX_HOSTLESS",
+ },
+ {
+ .playback = {
+ .stream_name = "SEC_I2S_RX Hostless Playback",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SEC_I2S_RX_HOSTLESS",
+ },
};
static __devinit int msm_fe_dai_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index a53dd44..c1304c8 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -90,6 +90,9 @@
SOC_ENUM_EXT("SEC RX Format", mi2s_config_enum[0],
msm_dai_q6_mi2s_format_get,
msm_dai_q6_mi2s_format_put),
+ SOC_ENUM_EXT("MI2S TX Format", mi2s_config_enum[0],
+ msm_dai_q6_mi2s_format_get,
+ msm_dai_q6_mi2s_format_put),
};
static u8 num_of_bits_set(u8 sd_line_mask)
@@ -238,7 +241,8 @@
}
if (mi2s_pdata->capability == MSM_MI2S_CAP_RX)
dai_driver->playback.channels_max = num_of_sd_lines << 1;
-
+ else if (mi2s_pdata->capability == MSM_MI2S_CAP_TX)
+ dai_driver->capture.channels_max = num_of_sd_lines << 1;
return 0;
error_invalid_data:
@@ -381,6 +385,7 @@
rc = msm_dai_q6_cdc_hw_params(params, dai, substream->stream);
break;
case MI2S_RX:
+ case MI2S_TX:
rc = msm_dai_q6_mi2s_hw_params(params, dai, substream->stream);
break;
case SLIMBUS_0_RX:
@@ -787,12 +792,13 @@
kfree(dai_data);
goto rtn;
}
- if (mi2s_pdata->capability == MSM_MI2S_CAP_RX) {
+ if (mi2s_pdata->capability == MSM_MI2S_CAP_RX)
kcontrol = &mi2s_config_controls[0];
- rc = snd_ctl_add(dai->card->snd_card,
- snd_ctl_new1(kcontrol, dai_data));
- }
+ else
+ kcontrol = &mi2s_config_controls[2];
+ rc = snd_ctl_add(dai->card->snd_card,
+ snd_ctl_new1(kcontrol, dai_data));
rtn:
return rc;
}
@@ -861,6 +867,7 @@
case PRIMARY_I2S_TX:
case PRIMARY_I2S_RX:
case MI2S_RX:
+ case MI2S_TX:
case SECONDARY_I2S_RX:
rc = msm_dai_q6_cdc_set_fmt(dai, fmt);
break;
@@ -1176,6 +1183,20 @@
.remove = msm_dai_q6_dai_probe,
};
+static struct snd_soc_dai_driver msm_dai_q6_mi2s_tx_dai = {
+ .capture = {
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .probe = msm_dai_q6_dai_mi2s_probe,
+ .remove = msm_dai_q6_dai_remove,
+};
+
static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_rx_dai = {
.playback = {
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
@@ -1247,6 +1268,10 @@
rc = snd_soc_register_dai(&pdev->dev,
&msm_dai_q6_mi2s_rx_dai);
break;
+ case MI2S_TX:
+ rc = snd_soc_register_dai(&pdev->dev,
+ &msm_dai_q6_mi2s_tx_dai);
+ break;
case SLIMBUS_0_RX:
case SLIMBUS_4_RX:
rc = snd_soc_register_dai(&pdev->dev,
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 0f74afb..18001b0 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -128,6 +128,7 @@
{ VOICE_RECORD_RX, 0, 0, 0, 0, 0},
{ VOICE_RECORD_TX, 0, 0, 0, 0, 0},
{ MI2S_RX, 0, 0, 0, 0, 0},
+ { MI2S_TX, 0, 0, 0, 0},
{ SECONDARY_I2S_RX, 0, 0, 0, 0, 0},
{ SLIMBUS_1_RX, 0, 0, 0, 0, 0},
{ SLIMBUS_1_TX, 0, 0, 0, 0, 0},
@@ -1023,6 +1024,9 @@
SOC_SINGLE_EXT("PRI_TX", MSM_BACKEND_DAI_PRI_I2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
@@ -1053,6 +1057,9 @@
SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
@@ -1164,6 +1171,9 @@
SOC_SINGLE_EXT("PRI_TX_Voice", MSM_BACKEND_DAI_PRI_I2S_TX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("MI2S_TX_Voice", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("SLIM_0_TX_Voice", MSM_BACKEND_DAI_SLIMBUS_0_TX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -1200,6 +1210,9 @@
SOC_SINGLE_EXT("PRI_TX_Voip", MSM_BACKEND_DAI_PRI_I2S_TX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("MI2S_TX_Voip", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("SLIM_0_TX_Voip", MSM_BACKEND_DAI_SLIMBUS_0_TX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -1236,6 +1249,9 @@
SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
};
static const struct snd_kcontrol_new auxpcm_rx_port_mixer_controls[] = {
@@ -1265,6 +1281,19 @@
msm_routing_put_port_mixer),
};
+
+static const struct snd_kcontrol_new hdmi_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
+static const struct snd_kcontrol_new sec_i2s_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
static const struct snd_kcontrol_new fm_switch_mixer_controls =
SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
0, 1, 0, msm_routing_get_switch_mixer,
@@ -1499,10 +1528,14 @@
SND_SOC_DAPM_AIF_OUT("INTFM_UL_HL", "INT_FM_HOSTLESS Capture",
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("HDMI_DL_HL", "HDMI_HOSTLESS Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_I2S_DL_HL", "SEC_I2S_RX_HOSTLESS Playback",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("AUXPCM_DL_HL", "AUXPCM_HOSTLESS Playback",
0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("AUXPCM_UL_HL", "AUXPCM_HOSTLESS Capture",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MI2S_UL_HL", "MI2S_TX_HOSTLESS Capture",
+ 0, 0, 0, 0),
/* Backend AIF */
/* Stream name equals to backend dai link stream name
@@ -1514,6 +1547,7 @@
SND_SOC_DAPM_AIF_OUT("HDMI", "HDMI Playback", 0, 0, 0 , 0),
SND_SOC_DAPM_AIF_OUT("MI2S_RX", "MI2S Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("PRI_I2S_TX", "Primary I2S Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MI2S_TX", "MI2S Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SLIMBUS_0_TX", "Slimbus Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("INT_BT_SCO_RX", "Internal BT-SCO Playback",
0, 0, 0 , 0),
@@ -1641,6 +1675,12 @@
SND_SOC_DAPM_MIXER("AFE_PCM_RX Port Mixer",
SND_SOC_NOPM, 0, 0, afe_pcm_rx_port_mixer_controls,
ARRAY_SIZE(afe_pcm_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("HDMI_RX Port Mixer",
+ SND_SOC_NOPM, 0, 0, hdmi_rx_port_mixer_controls,
+ ARRAY_SIZE(hdmi_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_I2S_RX Port Mixer",
+ SND_SOC_NOPM, 0, 0, sec_i2s_rx_port_mixer_controls,
+ ARRAY_SIZE(sec_i2s_rx_port_mixer_controls)),
};
static const struct snd_soc_dapm_route intercon[] = {
@@ -1686,6 +1726,8 @@
{"MI2S_RX", NULL, "MI2S_RX Audio Mixer"},
{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
+ {"MultiMedia1 Mixer", "MI2S_TX", "MI2S_TX"},
+ {"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
@@ -1758,6 +1800,7 @@
{"HDMI", NULL, "HDMI_DL_HL"},
{"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
+ {"Voice_Tx Mixer", "MI2S_TX_Voice", "MI2S_TX"},
{"Voice_Tx Mixer", "SLIM_0_TX_Voice", "SLIMBUS_0_TX"},
{"Voice_Tx Mixer", "INTERNAL_BT_SCO_TX_Voice", "INT_BT_SCO_TX"},
{"Voice_Tx Mixer", "AFE_PCM_TX_Voice", "PCM_TX"},
@@ -1770,6 +1813,7 @@
{"VoLTE_Tx Mixer", "AUX_PCM_TX_VoLTE", "AUX_PCM_TX"},
{"VoLTE_UL", NULL, "VoLTE_Tx Mixer"},
{"Voip_Tx Mixer", "PRI_TX_Voip", "PRI_I2S_TX"},
+ {"Voip_Tx Mixer", "MI2S_TX_Voip", "MI2S_TX"},
{"Voip_Tx Mixer", "SLIM_0_TX_Voip", "SLIMBUS_0_TX"},
{"Voip_Tx Mixer", "INTERNAL_BT_SCO_TX_Voip", "INT_BT_SCO_TX"},
{"Voip_Tx Mixer", "AFE_PCM_TX_Voip", "PCM_TX"},
@@ -1785,11 +1829,13 @@
{"AUXPCM_UL_HL", NULL, "AUX_PCM_TX"},
{"PCM_RX_DL_HL", "Switch", "SLIM0_DL_HL"},
{"PCM_RX", NULL, "PCM_RX_DL_HL"},
+ {"MI2S_UL_HL", NULL, "MI2S_TX"},
+ {"SEC_I2S_RX", NULL, "SEC_I2S_DL_HL"},
{"SLIMBUS_0_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"SLIMBUS_0_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"SLIMBUS_0_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"SLIMBUS_0_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
{"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Port Mixer"},
-
{"AFE_PCM_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"PCM_RX", NULL, "AFE_PCM_RX Port Mixer"},
@@ -1812,6 +1858,12 @@
{"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Port Mixer"},
{"INTERNAL_BT_SCO_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Port Mixer"},
+
+ {"HDMI_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
+ {"HDMI", NULL, "HDMI_RX Port Mixer"},
+
+ {"SEC_I2S_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
+ {"SEC_I2S_RX", NULL, "SEC_I2S_RX Port Mixer"},
};
static int msm_pcm_routing_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index e5d8638..546c396 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -32,6 +32,7 @@
#define LPASS_BE_SEC_I2S_RX "(Backend) SECONDARY_I2S_RX"
#define LPASS_BE_MI2S_RX "(Backend) MI2S_RX"
+#define LPASS_BE_MI2S_TX "(Backend) MI2S_TX"
#define LPASS_BE_STUB_RX "(Backend) STUB_RX"
#define LPASS_BE_STUB_TX "(Backend) STUB_TX"
#define LPASS_BE_SLIMBUS_1_RX "(Backend) SLIMBUS_1_RX"
@@ -81,6 +82,7 @@
MSM_BACKEND_DAI_INCALL_RECORD_RX,
MSM_BACKEND_DAI_INCALL_RECORD_TX,
MSM_BACKEND_DAI_MI2S_RX,
+ MSM_BACKEND_DAI_MI2S_TX,
MSM_BACKEND_DAI_SEC_I2S_RX,
MSM_BACKEND_DAI_SLIMBUS_1_RX,
MSM_BACKEND_DAI_SLIMBUS_1_TX,
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index abfadb8..44fab3f 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -254,6 +254,8 @@
{
struct snd_soc_dapm_context *dapm = &codec->dapm;
+ mutex_lock(&dapm->codec->mutex);
+
pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control);
if (msm8960_spk_control == MSM8960_SPK_ON) {
snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
@@ -268,6 +270,7 @@
}
snd_soc_dapm_sync(dapm);
+ mutex_unlock(&dapm->codec->mutex);
}
static int msm8960_get_spk(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index f47b0d3..4192609 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3811,6 +3811,7 @@
card->instantiated = 0;
mutex_init(&card->mutex);
mutex_init(&card->dapm_mutex);
+ mutex_init(&card->dapm_power_mutex);
mutex_init(&card->dsp_mutex);
spin_lock_init(&card->dsp_spinlock);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 265df9e..2284f19 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1306,15 +1306,24 @@
struct snd_soc_dapm_context *cur_dapm = NULL;
int ret, i;
int *sort;
+ int nWidgets;
if (power_up)
sort = dapm_up_seq;
else
sort = dapm_down_seq;
+ nWidgets = ARRAY_SIZE(dapm_up_seq);
+
list_for_each_entry_safe(w, n, list, power_list) {
ret = 0;
+ if (!w->name)
+ continue;
+
+ if (!((w->id >= 0) && (w->id < nWidgets)))
+ continue;
+
/* Do we need to apply any queued changes? */
if (sort[w->id] != cur_sort || w->reg != cur_reg ||
w->dapm != cur_dapm || w->subseq != cur_subseq) {
@@ -1500,6 +1509,8 @@
trace_snd_soc_dapm_start(card);
+ mutex_lock(&card->dapm_power_mutex);
+
list_for_each_entry(d, &card->dapm_list, list)
if (d->n_widgets || d->codec == NULL)
d->dev_power = 0;
@@ -1609,6 +1620,8 @@
"DAPM sequencing finished, waiting %dms\n", card->pop_time);
pop_wait(card->pop_time);
+ mutex_unlock(&card->dapm_power_mutex);
+
trace_snd_soc_dapm_done(card);
return 0;