Merge "msm: acpuclock-8960: Fix max CPU frequency limit for 8930." into msm-3.4
diff --git a/arch/arm/boot/dts/msmcopper.dtsi b/arch/arm/boot/dts/msmcopper.dtsi
index 5fe99df..bc7c5f0 100644
--- a/arch/arm/boot/dts/msmcopper.dtsi
+++ b/arch/arm/boot/dts/msmcopper.dtsi
@@ -402,6 +402,7 @@
compatible = "qcom,mdss_mdp";
reg = <0xfd900000 0x22100>;
interrupts = <0 72 0>;
+ vdd-supply = <&gdsc_mdss>;
};
qcom,mdss_wb_panel {
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index 8b9fa0fe..57cd263 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -173,6 +173,7 @@
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
CONFIG_MMC_PARANOID_SD_INIT=y
CONFIG_MMC_BLOCK_MINORS=32
# CONFIG_MMC_BLOCK_BOUNCE is not set
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index d53e471..c069761 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -238,7 +238,7 @@
static DEFINE_SPINLOCK(wakelock_reference_lock);
static int wakelock_reference_count;
static int a2_pc_disabled_wakelock_skipped;
-static int disconnect_ack;
+static int disconnect_ack = 1;
static LIST_HEAD(bam_other_notify_funcs);
static DEFINE_MUTEX(smsm_cb_lock);
static DEFINE_MUTEX(delayed_ul_vote_lock);
@@ -561,9 +561,9 @@
bam_dmux_log("%s: opening cid %d PC enabled\n", __func__,
rx_hdr->ch_id);
handle_bam_mux_cmd_open(rx_hdr);
- if (rx_hdr->reserved & ENABLE_DISCONNECT_ACK) {
- bam_dmux_log("%s: activating disconnect ack\n");
- disconnect_ack = 1;
+ if (!(rx_hdr->reserved & ENABLE_DISCONNECT_ACK)) {
+ bam_dmux_log("%s: deactivating disconnect ack\n");
+ disconnect_ack = 0;
}
dev_kfree_skb_any(rx_skb);
break;
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 622b213..7175123f 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -221,6 +221,7 @@
REGULATOR_SUPPLY("8921_lvs7", NULL),
REGULATOR_SUPPLY("pll_vdd", "pil_riva"),
REGULATOR_SUPPLY("lvds_vdda", "lvds.0"),
+ REGULATOR_SUPPLY("hdmi_pll_fs", "mdp.0"),
REGULATOR_SUPPLY("dsi1_vddio", "mipi_dsi.1"),
REGULATOR_SUPPLY("hdmi_vdda", "hdmi_msm.0"),
};
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 1f5ea52..1a61dbb 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -78,6 +78,7 @@
#include <mach/mdm2.h>
#include <mach/msm_rtb.h>
#include <linux/fmem.h>
+#include <mach/msm_cache_dump.h>
#ifdef CONFIG_INPUT_MPU3050
#include <linux/input/mpu3050.h>
@@ -629,6 +630,19 @@
msm8930_mdp_writeback(msm8930_reserve_table);
}
+#ifdef CONFIG_MSM_CACHE_DUMP
+static void __init reserve_cache_dump_memory(void)
+{
+ unsigned int total;
+
+ total = msm8930_cache_dump_pdata.l1_size +
+ msm8930_cache_dump_pdata.l2_size;
+ msm8930_reserve_table[MEMTYPE_EBI1].size += total;
+}
+#else
+static void __init reserve_cache_dump_memory(void) { }
+#endif
+
static void __init msm8930_calculate_reserve_sizes(void)
{
size_pmem_devices();
@@ -636,6 +650,7 @@
reserve_ion_memory();
reserve_mdp_memory();
reserve_rtb_memory();
+ reserve_cache_dump_memory();
}
static struct reserve_info msm8930_reserve_info __initdata = {
@@ -2149,6 +2164,7 @@
&msm8960_device_cache_erp,
&msm8930_iommu_domain_device,
&msm_tsens_device,
+ &msm8930_cache_dump_device,
};
static struct platform_device *cdp_devices[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8930.h b/arch/arm/mach-msm/board-8930.h
index 925de45..9f6276c 100644
--- a/arch/arm/mach-msm/board-8930.h
+++ b/arch/arm/mach-msm/board-8930.h
@@ -141,3 +141,4 @@
#define MSM_8930_GSBI12_QUP_I2C_BUS_ID 12
extern struct msm_rtb_platform_data msm8930_rtb_pdata;
+extern struct msm_cache_dump_platform_data msm8930_cache_dump_pdata;
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index bc5a892..6bd1b7d 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -116,6 +116,7 @@
REGULATOR_SUPPLY("8921_l23", NULL),
REGULATOR_SUPPLY("dsi_vddio", "mipi_dsi.1"),
REGULATOR_SUPPLY("hdmi_avdd", "hdmi_msm.0"),
+ REGULATOR_SUPPLY("hdmi_pll_fs", "mdp.0"),
REGULATOR_SUPPLY("pll_vdd", "pil_riva"),
REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.1"),
REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.2"),
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 628a324..ec62388 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -1416,6 +1416,7 @@
static struct msm_spi_platform_data msm8960_qup_spi_gsbi1_pdata = {
.max_clock_speed = 15060000,
+ .infinite_mode = 1
};
#ifdef CONFIG_USB_MSM_OTG_72K
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index b071353..0e2aa3b 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -89,6 +89,15 @@
#define GPIO_USER_FIRST 58
#define GPIO_USER_LAST 63
+#define GPIO_UIM_RESET 75
+#define GPIO_UIM_DATA_IO 76
+#define GPIO_UIM_CLOCK 77
+
+#define GPIO_PM_UIM_M_RST 26 /* UIM_RST input */
+#define GPIO_PM_UIM_RST 27 /* UIM_RST output */
+#define GPIO_PM_UIM_M_CLK 28 /* UIM_CLK input */
+#define GPIO_PM_UIM_CLK 29 /* UIM_CLK output */
+
#define FPGA_SDCC_STATUS 0x8E0001A8
/* Macros assume PMIC GPIOs start at 0 */
@@ -100,6 +109,8 @@
#define PMIC_GPIO_5V_PA_PWR 21 /* PMIC GPIO Number 22 */
#define PMIC_GPIO_4_2V_PA_PWR 22 /* PMIC GPIO Number 23 */
+#define PMIC_MPP_UIM_M_DATA 0 /* UIM_DATA input */
+#define PMIC_MPP_UIM_DATA 1 /* UIM_DATA output */
#define PMIC_MPP_3 2 /* PMIC MPP Number 3 */
#define PMIC_MPP_6 5 /* PMIC MPP Number 6 */
#define PMIC_MPP_7 6 /* PMIC MPP Number 7 */
@@ -181,6 +192,10 @@
PM8XXX_MPP_AOUT_LVL_1V25_2, AOUT_CTRL_ENABLE),
PM8XXX_MPP_INIT(PMIC_MPP_6, A_OUTPUT,
PM8XXX_MPP_AOUT_LVL_1V25_2, AOUT_CTRL_ENABLE),
+ PM8XXX_MPP_INIT(PMIC_MPP_UIM_M_DATA, D_BI_DIR,
+ PM8058_MPP_DIG_LEVEL_L3, BI_PULLUP_30KOHM),
+ PM8XXX_MPP_INIT(PMIC_MPP_UIM_DATA, D_BI_DIR,
+ PM8058_MPP_DIG_LEVEL_L3, BI_PULLUP_30KOHM),
};
for (i = 0; i < ARRAY_SIZE(pm8058_mpps); i++) {
@@ -597,6 +612,52 @@
}
#endif
+static struct msm_gpio uart3_uim_config_data[] = {
+ { GPIO_CFG(GPIO_UIM_RESET, 0, GPIO_CFG_OUTPUT,
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UIM_Reset" },
+ { GPIO_CFG(GPIO_UIM_DATA_IO, 2, GPIO_CFG_OUTPUT,
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UIM_Data" },
+ { GPIO_CFG(GPIO_UIM_CLOCK, 2, GPIO_CFG_OUTPUT,
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UIM_Clock" },
+};
+
+static void fsm9xxx_init_uart3_uim(void)
+{
+ struct pm_gpio pmic_uim_gpio_in = {
+ .direction = PM_GPIO_DIR_IN,
+ .pull = PM_GPIO_PULL_NO,
+ .out_strength = PM_GPIO_STRENGTH_HIGH,
+ .function = PM_GPIO_FUNC_PAIRED,
+ .vin_sel = PM8058_GPIO_VIN_L3,
+ };
+ struct pm_gpio pmic_uim_gpio_out = {
+ .direction = PM_GPIO_DIR_OUT,
+ .pull = PM_GPIO_PULL_NO,
+ .out_strength = PM_GPIO_STRENGTH_HIGH,
+ .function = PM_GPIO_FUNC_PAIRED,
+ .vin_sel = PM8058_GPIO_VIN_L3,
+ };
+
+ /* TLMM */
+ msm_gpios_request_enable(uart3_uim_config_data,
+ ARRAY_SIZE(uart3_uim_config_data));
+
+ /* Put UIM to reset state */
+ gpio_direction_output(GPIO_UIM_RESET, 0);
+ gpio_set_value(GPIO_UIM_RESET, 0);
+ gpio_export(GPIO_UIM_RESET, false);
+
+ /* PMIC */
+ pm8xxx_gpio_config(PM8058_GPIO_PM_TO_SYS(GPIO_PM_UIM_M_RST),
+ &pmic_uim_gpio_in);
+ pm8xxx_gpio_config(PM8058_GPIO_PM_TO_SYS(GPIO_PM_UIM_RST),
+ &pmic_uim_gpio_out);
+ pm8xxx_gpio_config(PM8058_GPIO_PM_TO_SYS(GPIO_PM_UIM_M_CLK),
+ &pmic_uim_gpio_in);
+ pm8xxx_gpio_config(PM8058_GPIO_PM_TO_SYS(GPIO_PM_UIM_CLK),
+ &pmic_uim_gpio_out);
+}
+
/*
* SSBI
*/
@@ -833,6 +894,7 @@
#if defined(CONFIG_SERIAL_MSM) || defined(CONFIG_MSM_SERIAL_DEBUGGER)
&msm_device_uart1,
#endif
+ &msm_device_uart3,
#if defined(CONFIG_QFP_FUSE)
&fsm_qfp_fuse_device,
#endif
@@ -903,6 +965,7 @@
#ifdef CONFIG_SERIAL_MSM_CONSOLE
fsm9xxx_init_uart1();
#endif
+ fsm9xxx_init_uart3_uim();
#ifdef CONFIG_I2C_SSBI
msm_device_ssbi2.dev.platform_data = &msm_i2c_ssbi2_pdata;
msm_device_ssbi3.dev.platform_data = &msm_i2c_ssbi3_pdata;
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 96d6055..481cd3d 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -4583,6 +4583,7 @@
DEFINE_CLK_RPM(mmfpb_clk, mmfpb_a_clk, MMFPB, NULL);
DEFINE_CLK_RPM(sfab_clk, sfab_a_clk, SYSTEM_FABRIC, NULL);
DEFINE_CLK_RPM(sfpb_clk, sfpb_a_clk, SFPB, NULL);
+DEFINE_CLK_RPM_QDSS(qdss_clk, qdss_a_clk);
static DEFINE_CLK_VOTER(sfab_msmbus_a_clk, &sfab_a_clk.c, 0);
static DEFINE_CLK_VOTER(sfab_tmr_a_clk, &sfab_a_clk.c, 0);
@@ -5068,6 +5069,8 @@
CLK_LOOKUP("mem_a_clk", ebi1_msmbus_a_clk.c, "msm_bus"),
CLK_LOOKUP("dfab_clk", dfab_msmbus_clk.c, "msm_bus"),
CLK_LOOKUP("dfab_a_clk", dfab_msmbus_a_clk.c, "msm_bus"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "msm_qdss"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "msm_qdss"),
CLK_LOOKUP("ebi1_clk", ebi1_clk.c, ""),
CLK_LOOKUP("mmfpb_clk", mmfpb_clk.c, ""),
@@ -5392,6 +5395,8 @@
CLK_LOOKUP("mem_a_clk", ebi1_msmbus_a_clk.c, "msm_bus"),
CLK_LOOKUP("dfab_clk", dfab_msmbus_clk.c, "msm_bus"),
CLK_LOOKUP("dfab_a_clk", dfab_msmbus_a_clk.c, "msm_bus"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "msm_qdss"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "msm_qdss"),
CLK_LOOKUP("ebi1_clk", ebi1_clk.c, NULL),
CLK_LOOKUP("mmfpb_clk", mmfpb_clk.c, NULL),
@@ -5708,6 +5713,8 @@
CLK_LOOKUP("mem_a_clk", ebi1_msmbus_a_clk.c, "msm_bus"),
CLK_LOOKUP("dfab_clk", dfab_msmbus_clk.c, "msm_bus"),
CLK_LOOKUP("dfab_a_clk", dfab_msmbus_a_clk.c, "msm_bus"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "msm_qdss"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "msm_qdss"),
CLK_LOOKUP("ebi1_clk", ebi1_clk.c, NULL),
CLK_LOOKUP("mmfpb_clk", mmfpb_clk.c, NULL),
diff --git a/arch/arm/mach-msm/clock-copper.c b/arch/arm/mach-msm/clock-copper.c
index 2dadc4c..fcb69f0 100644
--- a/arch/arm/mach-msm/clock-copper.c
+++ b/arch/arm/mach-msm/clock-copper.c
@@ -5017,6 +5017,7 @@
static void __init msmcopper_clock_post_init(void)
{
clk_set_rate(&axi_clk_src.c, 333330000);
+ clk_set_rate(&ocmemnoc_clk_src.c, 333330000);
/* Set rates for single-rate clocks. */
clk_set_rate(&usb30_master_clk_src.c,
diff --git a/arch/arm/mach-msm/clock-fsm9xxx.c b/arch/arm/mach-msm/clock-fsm9xxx.c
index 13a5b65..c188ba6 100644
--- a/arch/arm/mach-msm/clock-fsm9xxx.c
+++ b/arch/arm/mach-msm/clock-fsm9xxx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -24,6 +24,7 @@
static struct clk_lookup msm_clocks_fsm9xxx[] = {
CLK_DUMMY("core_clk", ADM0_CLK, "msm_dmov", OFF),
CLK_DUMMY("core_clk", UART1_CLK, "msm_serial.0", OFF),
+ CLK_DUMMY("core_clk", UART3_CLK, "msm_uim.2", OFF),
CLK_DUMMY("core_clk", CE_CLK, "qce.0", OFF),
CLK_DUMMY("core_clk", CE_CLK, "qcota.0", OFF),
CLK_DUMMY("core_clk", CE_CLK, "qcrypto.0", OFF),
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index e35e8d4..8096c10 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -51,7 +51,7 @@
int rc;
struct msm_rpm_iv_pair iv = { .id = r->rpm_status_id, };
rc = msm_rpm_get_status(&iv, 1);
- return (rc < 0) ? rc : iv.value * 1000;
+ return (rc < 0) ? rc : iv.value * r->factor;
}
#define RPM_SMD_KEY_RATE 0x007A484B
@@ -192,7 +192,7 @@
unsigned long this_khz, this_sleep_khz;
int rc = 0;
- this_khz = DIV_ROUND_UP(rate, 1000);
+ this_khz = DIV_ROUND_UP(rate, r->factor);
spin_lock_irqsave(&rpm_clock_lock, flags);
@@ -277,7 +277,7 @@
if (!r->branch) {
r->last_set_khz = iv.value;
r->last_set_sleep_khz = iv.value;
- clk->rate = iv.value * 1000;
+ clk->rate = iv.value * r->factor;
}
return HANDOFF_ENABLED_CLK;
diff --git a/arch/arm/mach-msm/clock-rpm.h b/arch/arm/mach-msm/clock-rpm.h
index b2358bc..107fb02 100644
--- a/arch/arm/mach-msm/clock-rpm.h
+++ b/arch/arm/mach-msm/clock-rpm.h
@@ -32,6 +32,7 @@
unsigned last_set_sleep_khz;
bool enabled;
bool branch; /* true: RPM only accepts 1 for ON and 0 for OFF */
+ unsigned factor;
struct clk_rpmrs_data *rpmrs_data;
struct rpm_clk *peer;
@@ -53,6 +54,7 @@
.rpm_clk_id = (r_id), \
.rpm_status_id = (stat_id), \
.peer = &active, \
+ .factor = 1000, \
.rpmrs_data = (rpmrsdata),\
.c = { \
.ops = &clk_ops_rpm, \
@@ -68,6 +70,7 @@
.rpm_status_id = (stat_id), \
.peer = &name, \
.active_only = true, \
+ .factor = 1000, \
.rpmrs_data = (rpmrsdata),\
.c = { \
.ops = &clk_ops_rpm, \
@@ -88,6 +91,7 @@
.peer = &active, \
.last_set_khz = ((r) / 1000), \
.last_set_sleep_khz = ((r) / 1000), \
+ .factor = 1000, \
.branch = true, \
.rpmrs_data = (rpmrsdata),\
.c = { \
@@ -106,6 +110,7 @@
.peer = &name, \
.last_set_khz = ((r) / 1000), \
.active_only = true, \
+ .factor = 1000, \
.branch = true, \
.rpmrs_data = (rpmrsdata),\
.c = { \
@@ -118,10 +123,48 @@
}, \
};
+#define __DEFINE_CLK_RPM_QDSS(name, active, type, r_id, stat_id, rpmrsdata) \
+ static struct rpm_clk active; \
+ static struct rpm_clk name = { \
+ .rpm_res_type = (type), \
+ .rpm_clk_id = (r_id), \
+ .rpm_status_id = (stat_id), \
+ .peer = &active, \
+ .factor = 1, \
+ .rpmrs_data = (rpmrsdata),\
+ .c = { \
+ .ops = &clk_ops_rpm, \
+ .flags = CLKFLAG_SKIP_AUTO_OFF, \
+ .dbg_name = #name, \
+ CLK_INIT(name.c), \
+ .warned = true, \
+ }, \
+ }; \
+ static struct rpm_clk active = { \
+ .rpm_res_type = (type), \
+ .rpm_clk_id = (r_id), \
+ .rpm_status_id = (stat_id), \
+ .peer = &name, \
+ .active_only = true, \
+ .factor = 1, \
+ .rpmrs_data = (rpmrsdata),\
+ .c = { \
+ .ops = &clk_ops_rpm, \
+ .flags = CLKFLAG_SKIP_AUTO_OFF, \
+ .dbg_name = #active, \
+ CLK_INIT(active.c), \
+ .warned = true, \
+ }, \
+ };
+
#define DEFINE_CLK_RPM(name, active, r_id, dep) \
__DEFINE_CLK_RPM(name, active, 0, MSM_RPM_ID_##r_id##_CLK, \
MSM_RPM_STATUS_ID_##r_id##_CLK, dep, &clk_rpmrs_data)
+#define DEFINE_CLK_RPM_QDSS(name, active) \
+ __DEFINE_CLK_RPM_QDSS(name, active, 0, MSM_RPM_ID_QDSS_CLK, \
+ MSM_RPM_STATUS_ID_QDSS_CLK, &clk_rpmrs_data)
+
#define DEFINE_CLK_RPM_BRANCH(name, active, r_id, r) \
__DEFINE_CLK_RPM_BRANCH(name, active, 0, MSM_RPM_ID_##r_id##_CLK, \
MSM_RPM_STATUS_ID_##r_id##_CLK, r, &clk_rpmrs_data)
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index c480bba..6ea8d7b 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -25,6 +25,7 @@
#include <mach/socinfo.h>
#include <mach/iommu_domains.h>
#include <mach/msm_rtb.h>
+#include <mach/msm_cache_dump.h>
#include "devices.h"
#include "rpm_log.h"
@@ -901,3 +902,23 @@
.platform_data = &msm8930_rtb_pdata,
},
};
+
+#define MSM8930_L1_SIZE SZ_1M
+/*
+ * The actual L2 size is smaller but we need a larger buffer
+ * size to store other dump information
+ */
+#define MSM8930_L2_SIZE SZ_4M
+
+struct msm_cache_dump_platform_data msm8930_cache_dump_pdata = {
+ .l2_size = MSM8930_L2_SIZE,
+ .l1_size = MSM8930_L1_SIZE,
+};
+
+struct platform_device msm8930_cache_dump_device = {
+ .name = "msm_cache_dump",
+ .id = -1,
+ .dev = {
+ .platform_data = &msm8930_cache_dump_pdata,
+ },
+};
diff --git a/arch/arm/mach-msm/devices-fsm9xxx.c b/arch/arm/mach-msm/devices-fsm9xxx.c
index 777b6d6..5f4d940 100644
--- a/arch/arm/mach-msm/devices-fsm9xxx.c
+++ b/arch/arm/mach-msm/devices-fsm9xxx.c
@@ -71,6 +71,26 @@
.resource = resources_uart2,
};
+static struct resource resources_uart3[] = {
+ {
+ .start = INT_UART3,
+ .end = INT_UART3,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = MSM_UART3_PHYS,
+ .end = MSM_UART3_PHYS + MSM_UART3_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device msm_device_uart3 = {
+ .name = "msm_uim",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(resources_uart3),
+ .resource = resources_uart3,
+};
+
/*
* SSBIs
*/
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 553f52f..1c58490 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -558,8 +558,8 @@
},
{
.name = "sdcc_dma_chnl",
- .start = DMOV_SDC3_CHAN,
- .end = DMOV_SDC3_CHAN,
+ .start = DMOV_NAND_CHAN,
+ .end = DMOV_NAND_CHAN,
.flags = IORESOURCE_DMA,
},
{
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index ff747e2..722575d 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -820,8 +820,8 @@
},
{
.name = "sdcc_dma_chnl",
- .start = DMOV_SDC2_CHAN,
- .end = DMOV_SDC2_CHAN,
+ .start = DMOV_NAND_CHAN,
+ .end = DMOV_NAND_CHAN,
.flags = IORESOURCE_DMA,
},
{
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index ea47727..152ca5b 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -406,6 +406,7 @@
extern struct platform_device msm8960_cache_dump_device;
extern struct platform_device apq8064_cache_dump_device;
+extern struct platform_device msm8930_cache_dump_device;
extern struct platform_device copper_device_tz_log;
diff --git a/arch/arm/mach-msm/footswitch-pcom.c b/arch/arm/mach-msm/footswitch-pcom.c
index 07d7118..8903859 100644
--- a/arch/arm/mach-msm/footswitch-pcom.c
+++ b/arch/arm/mach-msm/footswitch-pcom.c
@@ -42,7 +42,6 @@
* @init_data: Regulator platform data
* @pcom_id: Proc-comm ID of the footswitch
* @is_enabled: Flag set when footswitch is enabled
- * @is_manual: Flag set when footswitch is in manual proc-comm mode
* @has_ahb_clk: Flag set if footswitched core has an ahb_clk
* @has_src_clk: Flag set if footswitched core has a src_clk
* @src_clk: Controls the core clock's rate
@@ -57,7 +56,6 @@
struct regulator_init_data init_data;
unsigned pcom_id;
bool is_enabled;
- bool is_manual;
struct clk *src_clk;
struct clk *core_clk;
struct clk *ahb_clk;
@@ -256,12 +254,19 @@
if (pdev->id >= MAX_FS)
return -ENODEV;
- fs = &footswitches[pdev->id];
- if (!fs->is_manual) {
- pr_err("%s is not in manual mode\n", fs->desc.name);
- return -EINVAL;
- }
init_data = pdev->dev.platform_data;
+ fs = &footswitches[pdev->id];
+
+ /*
+ * Enable footswitch in manual mode (ie. not controlled along
+ * with pcom clocks).
+ */
+ rc = set_rail_state(fs->pcom_id, PCOM_CLKCTL_RPC_RAIL_ENABLE);
+ if (rc)
+ return rc;
+ rc = set_rail_mode(fs->pcom_id, PCOM_RAIL_MODE_MANUAL);
+ if (rc)
+ return rc;
rc = get_clocks(&pdev->dev, fs);
if (rc)
@@ -305,21 +310,6 @@
static int __init footswitch_init(void)
{
- struct footswitch *fs;
- int ret;
-
- /*
- * Enable all footswitches in manual mode (ie. not controlled along
- * with pcom clocks).
- */
- for (fs = footswitches; fs < footswitches + ARRAY_SIZE(footswitches);
- fs++) {
- set_rail_state(fs->pcom_id, PCOM_CLKCTL_RPC_RAIL_ENABLE);
- ret = set_rail_mode(fs->pcom_id, PCOM_RAIL_MODE_MANUAL);
- if (!ret)
- fs->is_manual = 1;
- }
-
return platform_driver_register(&footswitch_driver);
}
subsys_initcall(footswitch_init);
diff --git a/arch/arm/mach-msm/gdsc.c b/arch/arm/mach-msm/gdsc.c
index df3a92d..f91e3dc 100644
--- a/arch/arm/mach-msm/gdsc.c
+++ b/arch/arm/mach-msm/gdsc.c
@@ -63,10 +63,18 @@
ret = readl_tight_poll_timeout(sc->gdscr, regval, regval & PWR_ON_MASK,
TIMEOUT_US);
- if (ret)
+ if (ret) {
dev_err(&rdev->dev, "%s enable timed out\n", sc->rdesc.name);
+ return ret;
+ }
- return ret;
+ /*
+ * If clocks to this power domain were already on, they will take an
+ * additional 4 clock cycles to re-enable after the rail is enabled.
+ */
+ udelay(1);
+
+ return 0;
}
static int gdsc_disable(struct regulator_dev *rdev)
diff --git a/arch/arm/mach-msm/gss-8064.c b/arch/arm/mach-msm/gss-8064.c
index 126f8e0..e65f2d2 100644
--- a/arch/arm/mach-msm/gss-8064.c
+++ b/arch/arm/mach-msm/gss-8064.c
@@ -69,40 +69,12 @@
wmb();
}
-static void gss_fatal_fn(struct work_struct *work)
+static void restart_gss(void)
{
- uint32_t panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
- uint32_t reset_smsm_states = SMSM_SYSTEM_REBOOT_USR |
- SMSM_SYSTEM_PWRDWN_USR;
- uint32_t gss_state;
-
- pr_err("Watchdog bite received from GSS!\n");
-
- gss_state = smsm_get_state(SMSM_MODEM_STATE);
-
- if (gss_state & panic_smsm_states) {
-
- pr_err("GSS SMSM state changed to SMSM_RESET.\n"
- "Probable err_fatal on the GSS. "
- "Calling subsystem restart...\n");
- log_gss_sfr();
- subsystem_restart("gss");
-
- } else if (gss_state & reset_smsm_states) {
-
- pr_err("%s: User-invoked system reset/powerdown. "
- "Resetting the SoC now.\n",
- __func__);
- kernel_restart(NULL);
- } else {
- /* TODO: Bus unlock code/sequence goes _here_ */
- log_gss_sfr();
- subsystem_restart("gss");
- }
+ log_gss_sfr();
+ subsystem_restart("gss");
}
-static DECLARE_WORK(gss_fatal_work, gss_fatal_fn);
-
static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
{
/* Ignore if we're the one that set SMSM_RESET */
@@ -113,8 +85,7 @@
pr_err("GSS SMSM state changed to SMSM_RESET.\n"
"Probable err_fatal on the GSS. "
"Calling subsystem restart...\n");
- log_gss_sfr();
- subsystem_restart("gss");
+ restart_gss();
}
}
@@ -180,8 +151,8 @@
static irqreturn_t gss_wdog_bite_irq(int irq, void *dev_id)
{
- schedule_work(&gss_fatal_work);
- disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
+ pr_err("Watchdog bite received from GSS!\n");
+ restart_gss();
return IRQ_HANDLED;
}
diff --git a/arch/arm/mach-msm/include/mach/mdm2.h b/arch/arm/mach-msm/include/mach/mdm2.h
index 09839b2..2bcdf07 100644
--- a/arch/arm/mach-msm/include/mach/mdm2.h
+++ b/arch/arm/mach-msm/include/mach/mdm2.h
@@ -27,6 +27,7 @@
int soft_reset_inverted;
int early_power_on;
int sfr_query;
+ int no_powerdown_after_ramdumps;
struct mdm_vddmin_resource *vddmin_resource;
struct platform_device *peripheral_platform_device;
};
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-fsm9xxx.h b/arch/arm/mach-msm/include/mach/msm_iomap-fsm9xxx.h
index c30c9e4..a99f1f7 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-fsm9xxx.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-fsm9xxx.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -78,7 +78,10 @@
#define MSM_UART1_PHYS 0x94000000
#define MSM_UART1_SIZE SZ_4K
-#define MSM_UART2_PHYS 0x94100000
+#define MSM_UART2_PHYS 0x94010000
#define MSM_UART2_SIZE SZ_4K
+#define MSM_UART3_PHYS 0x94100000
+#define MSM_UART3_SIZE SZ_4K
+
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_spi.h b/arch/arm/mach-msm/include/mach/msm_spi.h
index 51081b6..11d3014 100644
--- a/arch/arm/mach-msm/include/mach/msm_spi.h
+++ b/arch/arm/mach-msm/include/mach/msm_spi.h
@@ -21,4 +21,5 @@
int (*dma_config)(void);
const char *rsl_id;
uint32_t pm_lat;
+ uint32_t infinite_mode;
};
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index 4791955..f851545 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.c
@@ -42,9 +42,6 @@
#include "clock.h"
#include "mdm_private.h"
-#define MDM_MODEM_TIMEOUT 6000
-#define MDM_HOLD_TIME 4000
-#define MDM_MODEM_DELTA 100
#define MDM_PBLRDY_CNT 20
static int mdm_debug_on;
@@ -80,20 +77,52 @@
mutex_unlock(&hsic_status_lock);
}
+static void mdm_toggle_soft_reset(struct mdm_modem_drv *mdm_drv)
+{
+ int soft_reset_direction_assert = 0,
+ soft_reset_direction_de_assert = 1;
+
+ if (mdm_drv->pdata->soft_reset_inverted) {
+ soft_reset_direction_assert = 1;
+ soft_reset_direction_de_assert = 0;
+ }
+ gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
+ soft_reset_direction_assert);
+ usleep_range(5000, 10000);
+ gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
+ soft_reset_direction_de_assert);
+}
+
static void mdm_power_down_common(struct mdm_modem_drv *mdm_drv)
{
+ int i;
int soft_reset_direction =
mdm_drv->pdata->soft_reset_inverted ? 1 : 0;
- gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
- soft_reset_direction);
+ /* Wait for the modem to complete its power down actions. */
+ for (i = 20; i > 0; i--) {
+ if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
+ break;
+ msleep(100);
+ }
+ if (i == 0) {
+ pr_err("%s: MDM2AP_STATUS never went low. Doing a hard reset\n",
+ __func__);
+ gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
+ soft_reset_direction);
+ /*
+ * Currently, there is a debounce timer on the charm PMIC. It is
+ * necessary to hold the PMIC RESET low for ~3.5 seconds
+ * for the reset to fully take place. Sleep here to ensure the
+ * reset has occured before the function exits.
+ */
+ msleep(4000);
+ }
mdm_peripheral_disconnect(mdm_drv);
}
static void mdm_do_first_power_on(struct mdm_modem_drv *mdm_drv)
{
- int soft_reset_direction =
- mdm_drv->pdata->soft_reset_inverted ? 0 : 1;
int i;
int pblrdy;
@@ -106,6 +135,13 @@
pr_err("%s: Powering on modem for the first time\n", __func__);
mdm_peripheral_disconnect(mdm_drv);
+ /* If this is the first power-up after a panic, the modem may still
+ * be in a power-on state, in which case we need to toggle the gpio
+ * instead of just de-asserting it. No harm done if the modem was
+ * powered down.
+ */
+ mdm_toggle_soft_reset(mdm_drv);
+
/* If the device has a kpd pwr gpio then toggle it. */
if (mdm_drv->ap2mdm_kpdpwr_n_gpio > 0) {
/* Pull AP2MDM_KPDPWR gpio high and wait for PS_HOLD to settle,
@@ -117,10 +153,6 @@
gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 0);
}
- /* De-assert the soft reset line. */
- pr_debug("%s: De-asserting soft reset gpio\n", __func__);
- gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
- soft_reset_direction);
if (!mdm_drv->mdm2ap_pblrdy)
goto start_mdm_peripheral;
@@ -140,21 +172,12 @@
static void mdm_do_soft_power_on(struct mdm_modem_drv *mdm_drv)
{
- int soft_reset_direction =
- mdm_drv->pdata->soft_reset_inverted ? 0 : 1;
int i;
int pblrdy;
- /* De-assert the soft reset line. */
pr_err("%s: soft resetting mdm modem\n", __func__);
-
mdm_peripheral_disconnect(mdm_drv);
-
- gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
- soft_reset_direction == 1 ? 0 : 1);
- usleep_range(5000, 10000);
- gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
- soft_reset_direction == 1 ? 1 : 0);
+ mdm_toggle_soft_reset(mdm_drv);
if (!mdm_drv->mdm2ap_pblrdy)
goto start_mdm_peripheral;
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index c961731..04ce49f 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -45,7 +45,7 @@
#define MDM_MODEM_TIMEOUT 6000
#define MDM_MODEM_DELTA 100
#define MDM_BOOT_TIMEOUT 60000L
-#define MDM_RDUMP_TIMEOUT 60000L
+#define MDM_RDUMP_TIMEOUT 120000L
#define MDM2AP_STATUS_TIMEOUT_MS 60000L
static int mdm_debug_on;
@@ -403,7 +403,8 @@
pr_info("%s: mdm modem ramdumps completed.\n",
__func__);
INIT_COMPLETION(mdm_ram_dumps);
- mdm_drv->ops->power_down_mdm_cb(mdm_drv);
+ if (!mdm_drv->pdata->no_powerdown_after_ramdumps)
+ mdm_drv->ops->power_down_mdm_cb(mdm_drv);
}
return mdm_drv->mdm_ram_dump_status;
}
diff --git a/arch/arm/mach-msm/perf_event_msm_krait_l2.c b/arch/arm/mach-msm/perf_event_msm_krait_l2.c
index 22dbff3..5f76a92 100644
--- a/arch/arm/mach-msm/perf_event_msm_krait_l2.c
+++ b/arch/arm/mach-msm/perf_event_msm_krait_l2.c
@@ -21,6 +21,10 @@
#define MAX_L2_PERIOD ((1ULL << 32) - 1)
#define MAX_KRAIT_L2_CTRS 5
+#define L2_EVT_MASK 0xfffff
+
+#define L2_SLAVE_EV_PREFIX 4
+
#define L2PMCCNTR 0x409
#define L2PMCCNTCR 0x408
#define L2PMCCNTSR 0x40A
@@ -49,9 +53,12 @@
/* event format is -e rsRCCG See get_event_desc() */
-#define EVENT_REG_MASK 0xf000
-#define EVENT_GROUPSEL_MASK 0x000f
-#define EVENT_GROUPCODE_MASK 0x0ff0
+#define EVENT_PREFIX_MASK 0xf0000
+#define EVENT_REG_MASK 0x0f000
+#define EVENT_GROUPSEL_MASK 0x0000f
+#define EVENT_GROUPCODE_MASK 0x00ff0
+
+#define EVENT_PREFIX_SHIFT 16
#define EVENT_REG_SHIFT 12
#define EVENT_GROUPCODE_SHIFT 4
@@ -70,11 +77,13 @@
};
/* NRCCG format for perf RAW codes. */
+PMU_FORMAT_ATTR(l2_prefix, "config:16-19");
PMU_FORMAT_ATTR(l2_reg, "config:12-15");
PMU_FORMAT_ATTR(l2_code, "config:4-11");
PMU_FORMAT_ATTR(l2_grp, "config:0-3");
static struct attribute *msm_l2_ev_formats[] = {
+ &format_attr_l2_prefix.attr,
&format_attr_l2_reg.attr,
&format_attr_l2_code.attr,
&format_attr_l2_grp.attr,
@@ -97,6 +106,9 @@
static u32 l2_orig_filter_prefix = 0x000f0030;
+/* L2 slave port traffic filtering */
+static u32 l2_slv_filter_prefix = 0x000f0010;
+
static u32 pmu_type;
static struct arm_pmu krait_l2_pmu;
@@ -167,19 +179,25 @@
set_l2_indirect_reg(group_reg, resr_val);
}
-static void set_evfilter_task_mode(int ctr)
+static void set_evfilter_task_mode(int ctr, unsigned int is_slv)
{
u32 filter_reg = (ctr * 16) + IA_L2PMXEVFILTER_BASE;
u32 filter_val = l2_orig_filter_prefix | 1 << smp_processor_id();
+ if (is_slv)
+ filter_val = l2_slv_filter_prefix;
+
set_l2_indirect_reg(filter_reg, filter_val);
}
-static void set_evfilter_sys_mode(int ctr)
+static void set_evfilter_sys_mode(int ctr, unsigned int is_slv)
{
u32 filter_reg = (ctr * 16) + IA_L2PMXEVFILTER_BASE;
u32 filter_val = l2_orig_filter_prefix | 0xf;
+ if (is_slv)
+ filter_val = l2_slv_filter_prefix;
+
set_l2_indirect_reg(filter_reg, filter_val);
}
@@ -251,12 +269,21 @@
{
struct event_desc evdesc;
unsigned long iflags;
+ unsigned int is_slv = 0;
+ unsigned int evt_prefix;
raw_spin_lock_irqsave(&krait_l2_pmu_hw_events.pmu_lock, iflags);
if (hwc->config_base == L2CYCLE_CTR_RAW_CODE)
goto out;
+ /* Check if user requested any special origin filtering. */
+ evt_prefix = (hwc->config_base &
+ EVENT_PREFIX_MASK) >> EVENT_PREFIX_SHIFT;
+
+ if (evt_prefix == L2_SLAVE_EV_PREFIX)
+ is_slv = 1;
+
set_evcntcr(idx);
memset(&evdesc, 0, sizeof(evdesc));
@@ -269,9 +296,9 @@
evdesc.event_group_code);
if (cpu < 0)
- set_evfilter_task_mode(idx);
+ set_evfilter_task_mode(idx, is_slv);
else
- set_evfilter_sys_mode(idx);
+ set_evfilter_sys_mode(idx, is_slv);
out:
enable_intenset(idx);
@@ -397,7 +424,7 @@
static int krait_l2_map_event(struct perf_event *event)
{
if (pmu_type > 0 && pmu_type == event->attr.type)
- return event->attr.config & 0xffff;
+ return event->attr.config & L2_EVT_MASK;
else
return -ENOENT;
}
@@ -419,7 +446,7 @@
static int msm_l2_test_set_ev_constraint(struct perf_event *event)
{
- u32 evt_type = event->attr.config & 0xffff;
+ u32 evt_type = event->attr.config & L2_EVT_MASK;
u8 reg = (evt_type & 0x0F000) >> 12;
u8 group = evt_type & 0x0000F;
unsigned long flags;
@@ -444,7 +471,7 @@
static int msm_l2_clear_ev_constraint(struct perf_event *event)
{
- u32 evt_type = event->attr.config & 0xffff;
+ u32 evt_type = event->attr.config & L2_EVT_MASK;
u8 reg = (evt_type & 0x0F000) >> 12;
u8 group = evt_type & 0x0000F;
unsigned long flags;
@@ -476,7 +503,7 @@
.read_counter = krait_l2_read_counter,
.write_counter = krait_l2_write_counter,
.map_event = krait_l2_map_event,
- .max_period = (1LLU << 32) - 1,
+ .max_period = MAX_L2_PERIOD,
.get_hw_events = krait_l2_get_hw_events,
.num_events = MAX_KRAIT_L2_CTRS,
.test_set_event_constraints = msm_l2_test_set_ev_constraint,
diff --git a/arch/arm/mach-msm/perf_event_msm_l2.c b/arch/arm/mach-msm/perf_event_msm_l2.c
index e3ab64a..5a5bf57 100644
--- a/arch/arm/mach-msm/perf_event_msm_l2.c
+++ b/arch/arm/mach-msm/perf_event_msm_l2.c
@@ -24,6 +24,11 @@
#define SCORPION_L2_EVT_PREFIX 3
#define SCORPION_MAX_L2_REG 4
+#define L2_EVT_MASK 0xfffff
+#define L2_EVT_PREFIX_MASK 0xf0000
+#define L2_EVT_PREFIX_SHIFT 16
+#define L2_SLAVE_EVT_PREFIX 4
+
/*
* The L2 PMU is shared between all CPU's, so protect
@@ -69,6 +74,11 @@
static struct arm_pmu scorpion_l2_pmu;
+static u32 l2_orig_filter_prefix = 0x000f0030;
+
+/* L2 slave port traffic filtering */
+static u32 l2_slv_filter_prefix = 0x000f0010;
+
static struct perf_event *l2_events[MAX_SCORPION_L2_CTRS];
static unsigned long l2_used_mask[BITS_TO_LONGS(MAX_SCORPION_L2_CTRS)];
@@ -418,7 +428,8 @@
u8 group;
prefix = (evt_type & 0xF0000) >> 16;
- if (prefix == SCORPION_L2_EVT_PREFIX) {
+ if (prefix == SCORPION_L2_EVT_PREFIX ||
+ prefix == L2_SLAVE_EVT_PREFIX) {
reg = (evt_type & 0x0F000) >> 12;
code = (evt_type & 0x00FF0) >> 4;
group = evt_type & 0x0000F;
@@ -475,16 +486,22 @@
asm volatile ("mcr p15, 3, %0, c15, c6, 7" : : "r" (val));
}
-static void scorpion_l2_set_evfilter_task_mode(void)
+static void scorpion_l2_set_evfilter_task_mode(unsigned int is_slv)
{
- u32 filter_val = 0x000f0030 | 1 << smp_processor_id();
+ u32 filter_val = l2_orig_filter_prefix | 1 << smp_processor_id();
+
+ if (is_slv)
+ filter_val = l2_slv_filter_prefix;
asm volatile ("mcr p15, 3, %0, c15, c6, 3" : : "r" (filter_val));
}
-static void scorpion_l2_set_evfilter_sys_mode(void)
+static void scorpion_l2_set_evfilter_sys_mode(unsigned int is_slv)
{
- u32 filter_val = 0x000f003f;
+ u32 filter_val = l2_orig_filter_prefix | 0xf;
+
+ if (is_slv)
+ filter_val = l2_slv_filter_prefix;
asm volatile ("mcr p15, 3, %0, c15, c6, 3" : : "r" (filter_val));
}
@@ -584,12 +601,21 @@
int evtype = hwc->config_base;
int ev_typer;
unsigned long iflags;
+ unsigned int is_slv = 0;
+ unsigned int evt_prefix;
raw_spin_lock_irqsave(&scorpion_l2_pmu_hw_events.pmu_lock, iflags);
if (hwc->config_base == SCORPION_L2CYCLE_CTR_RAW_CODE)
goto out;
+ /* Check if user requested any special origin filtering. */
+ evt_prefix = (hwc->config_base &
+ L2_EVT_PREFIX_MASK) >> L2_EVT_PREFIX_SHIFT;
+
+ if (evt_prefix == L2_SLAVE_EVT_PREFIX)
+ is_slv = 1;
+
memset(&evtinfo, 0, sizeof(evtinfo));
ev_typer = get_scorpion_l2_evtinfo(evtype, &evtinfo);
@@ -599,9 +625,9 @@
scorpion_l2_set_evcntcr();
if (cpu < 0)
- scorpion_l2_set_evfilter_task_mode();
+ scorpion_l2_set_evfilter_task_mode(is_slv);
else
- scorpion_l2_set_evfilter_sys_mode();
+ scorpion_l2_set_evfilter_sys_mode(is_slv);
scorpion_l2_evt_setup(evtinfo.grp, evtinfo.val);
@@ -735,7 +761,7 @@
static int scorpion_l2_map_event(struct perf_event *event)
{
if (pmu_type > 0 && pmu_type == event->attr.type)
- return event->attr.config & 0xfffff;
+ return event->attr.config & L2_EVT_MASK;
else
return -ENOENT;
}
@@ -757,7 +783,7 @@
static int msm_l2_test_set_ev_constraint(struct perf_event *event)
{
- u32 evt_type = event->attr.config & 0xfffff;
+ u32 evt_type = event->attr.config & L2_EVT_MASK;
u8 prefix = (evt_type & 0xF0000) >> 16;
u8 reg = (evt_type & 0x0F000) >> 12;
u8 group = evt_type & 0x0000F;
@@ -787,7 +813,7 @@
static int msm_l2_clear_ev_constraint(struct perf_event *event)
{
- u32 evt_type = event->attr.config & 0xfffff;
+ u32 evt_type = event->attr.config & L2_EVT_MASK;
u8 prefix = (evt_type & 0xF0000) >> 16;
u8 reg = (evt_type & 0x0F000) >> 12;
u8 group = evt_type & 0x0000F;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_lpa.c b/arch/arm/mach-msm/qdsp5v2/audio_lpa.c
index d5fb2e9..60f43b9 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_lpa.c
@@ -34,6 +34,7 @@
#include <linux/slab.h>
#include <linux/msm_audio.h>
#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <linux/memory_alloc.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
@@ -1410,7 +1411,7 @@
wake_up(&audio->event_wait);
audlpa_reset_event_queue(audio);
iounmap(audio->data);
- pmem_kfree(audio->phys);
+ free_contiguous_memory_by_paddr(audio->phys);
mutex_unlock(&audio->lock);
#ifdef CONFIG_DEBUG_FS
if (audio->dentry)
@@ -1655,7 +1656,7 @@
msm_adsp_put(audio->audplay);
err:
iounmap(audio->data);
- pmem_kfree(audio->phys);
+ free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_mvs.c b/arch/arm/mach-msm/qdsp5v2/audio_mvs.c
index 99da836..1884b3c 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_mvs.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_mvs.c
@@ -304,6 +304,7 @@
uint32_t buf_free_cnt;
uint32_t rate_type;
uint32_t dtx_mode;
+ struct min_max_rate min_max_rate;
struct msm_rpc_endpoint *rpc_endpt;
uint32_t rpc_prog;
@@ -416,8 +417,10 @@
/* Set EVRC mode. */
memset(&set_voc_mode_msg, 0, sizeof(set_voc_mode_msg));
- set_voc_mode_msg.min_rate = cpu_to_be32(audio->rate_type);
- set_voc_mode_msg.max_rate = cpu_to_be32(audio->rate_type);
+ set_voc_mode_msg.min_rate =
+ cpu_to_be32(audio->min_max_rate.min_rate);
+ set_voc_mode_msg.max_rate =
+ cpu_to_be32(audio->min_max_rate.max_rate);
msm_rpc_setup_req(&set_voc_mode_msg.rpc_hdr,
audio->rpc_prog,
@@ -1555,6 +1558,8 @@
mutex_lock(&audio->lock);
config.mvs_mode = audio->mvs_mode;
config.rate_type = audio->rate_type;
+ config.min_max_rate.min_rate = audio->min_max_rate.min_rate;
+ config.min_max_rate.max_rate = audio->min_max_rate.max_rate;
mutex_unlock(&audio->lock);
rc = copy_to_user((void *)arg, &config, sizeof(config));
@@ -1579,6 +1584,10 @@
audio->mvs_mode = config.mvs_mode;
audio->rate_type = config.rate_type;
audio->dtx_mode = config.dtx_mode;
+ audio->min_max_rate.min_rate =
+ config.min_max_rate.min_rate;
+ audio->min_max_rate.max_rate =
+ config.min_max_rate.max_rate;
} else {
pr_err("%s: Set confg called in state %d\n",
__func__, audio->state);
diff --git a/arch/arm/mach-msm/sdio_ctl.c b/arch/arm/mach-msm/sdio_ctl.c
index 586e890..ac16e77 100644
--- a/arch/arm/mach-msm/sdio_ctl.c
+++ b/arch/arm/mach-msm/sdio_ctl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -25,6 +25,7 @@
#include <linux/mutex.h>
#include <linux/uaccess.h>
#include <linux/workqueue.h>
+#include <linux/poll.h>
#include <asm/ioctls.h>
#include <linux/platform_device.h>
#include <mach/msm_smd.h>
@@ -206,6 +207,34 @@
return ret;
}
+static unsigned int sdio_ctl_poll(struct file *file, poll_table *wait)
+{
+ struct sdio_ctl_dev *sdio_ctl_devp;
+ unsigned int mask = 0;
+
+ sdio_ctl_devp = file->private_data;
+ if (!sdio_ctl_devp) {
+ pr_err("%s: on a NULL device\n", __func__);
+ return POLLERR;
+ }
+
+ poll_wait(file, &sdio_ctl_devp->read_wait_queue, wait);
+ mutex_lock(&sdio_ctl_devp->rx_lock);
+ if (sdio_cmux_is_channel_reset(sdio_ctl_devp->id)) {
+ mutex_unlock(&sdio_ctl_devp->rx_lock);
+ pr_err("%s notifying reset for sdio_ctl_dev id:%d\n",
+ __func__, sdio_ctl_devp->id);
+ return POLLERR;
+ }
+
+ if (sdio_ctl_devp->read_avail > 0)
+ mask |= POLLIN | POLLRDNORM;
+
+ mutex_unlock(&sdio_ctl_devp->rx_lock);
+
+ return mask;
+}
+
ssize_t sdio_ctl_read(struct file *file,
char __user *buf,
size_t count,
@@ -417,6 +446,7 @@
.release = sdio_ctl_release,
.read = sdio_ctl_read,
.write = sdio_ctl_write,
+ .poll = sdio_ctl_poll,
.unlocked_ioctl = sdio_ctl_ioctl,
};
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index b047cf4..533e6cd 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -189,12 +189,14 @@
[88] = MSM_CPU_7X25A,
[89] = MSM_CPU_7X25A,
[96] = MSM_CPU_7X25A,
+ [135] = MSM_CPU_7X25A,
/* 7x27A IDs */
[90] = MSM_CPU_7X27A,
[91] = MSM_CPU_7X27A,
[92] = MSM_CPU_7X27A,
[97] = MSM_CPU_7X27A,
+ [136] = MSM_CPU_7X27A,
/* FSM9xxx ID */
[94] = FSM_CPU_9XXX,
diff --git a/drivers/gpu/msm/kgsl_drm.c b/drivers/gpu/msm/kgsl_drm.c
index 66ac08f..870a7d7 100644
--- a/drivers/gpu/msm/kgsl_drm.c
+++ b/drivers/gpu/msm/kgsl_drm.c
@@ -238,11 +238,8 @@
}
if (TYPE_IS_PMEM(priv->type)) {
- int type;
-
if (priv->type == DRM_KGSL_GEM_TYPE_EBI ||
priv->type & DRM_KGSL_GEM_PMEM_EBI) {
- type = PMEM_MEMTYPE_EBI1;
result = kgsl_sharedmem_ebimem_user(
&priv->memdesc,
priv->pagetable,
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index a2993ce..116b7f9 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -3453,9 +3453,17 @@
if (retval < 0)
FMDBG("write failed");
} break;
+ case V4L2_CID_PRIVATE_SOFT_MUTE:
+ radio->registers[IOCTRL] &= ~(IOC_SFT_MUTE);
+ if (ctrl->value)
+ radio->registers[IOCTRL] |= IOC_SFT_MUTE;
+ retval = tavarua_write_register(radio, IOCTRL,
+ radio->registers[IOCTRL]);
+ if (retval < 0)
+ FMDERR("Failed to enable/disable SMute\n");
+ break;
/*These IOCTL's are place holders to keep the
driver compatible with change in frame works for IRIS */
- case V4L2_CID_PRIVATE_SOFT_MUTE:
case V4L2_CID_PRIVATE_RIVA_ACCS_ADDR:
case V4L2_CID_PRIVATE_RIVA_ACCS_LEN:
case V4L2_CID_PRIVATE_RIVA_PEEK:
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index 5ffc133..9c791e4 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -271,6 +271,15 @@
cores and composite them into a single
interrupt to the MSM.
+config MSM_CPP
+ bool "Qualcomm MSM Camera Post Processing Engine support"
+ depends on MSM_CAMERA && MSM_CAMERA_V4L2
+ ---help---
+ Enable support for Camera Post-processing Engine
+ The Post processing engine is capable of scaling
+ and cropping image. The driver support V4L2 subdev
+ APIs.
+
config QUP_EXCLUSIVE_TO_CAMERA
bool "QUP exclusive to camera"
depends on MSM_CAMERA
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 431da2e..63120da 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -13,6 +13,7 @@
EXTRA_CFLAGS += -Idrivers/media/video/msm/server
obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o
obj-$(CONFIG_MSM_CAMERA) += server/ eeprom/ sensors/ actuators/ csi/
+ obj-$(CONFIG_MSM_CPP) += cpp/
obj-$(CONFIG_MSM_CAMERA) += msm_gesture.o
obj-$(CONFIG_MSM_CAM_IRQ_ROUTER) += msm_camirq_router.o
else
diff --git a/drivers/media/video/msm/actuators/msm_actuator.c b/drivers/media/video/msm/actuators/msm_actuator.c
index 774a46d..554cddc 100644
--- a/drivers/media/video/msm/actuators/msm_actuator.c
+++ b/drivers/media/video/msm/actuators/msm_actuator.c
@@ -14,55 +14,42 @@
#include "msm_actuator.h"
static struct msm_actuator_ctrl_t msm_actuator_t;
-
-static struct msm_actuator msm_vcm_actuator_table = {
- .act_type = ACTUATOR_VCM,
- .func_tbl = {
- .actuator_init_step_table = msm_actuator_init_step_table,
- .actuator_move_focus = msm_actuator_move_focus,
- .actuator_write_focus = msm_actuator_write_focus,
- .actuator_set_default_focus = msm_actuator_set_default_focus,
- .actuator_init_focus = msm_actuator_init_focus,
- .actuator_i2c_write = msm_actuator_i2c_write,
- },
-};
-
-static struct msm_actuator msm_piezo_actuator_table = {
- .act_type = ACTUATOR_PIEZO,
- .func_tbl = {
- .actuator_init_step_table = NULL,
- .actuator_move_focus = msm_actuator_piezo_move_focus,
- .actuator_write_focus = NULL,
- .actuator_set_default_focus =
- msm_actuator_piezo_set_default_focus,
- .actuator_init_focus = msm_actuator_init_focus,
- .actuator_i2c_write = msm_actuator_i2c_write,
- },
-};
+static struct msm_actuator msm_vcm_actuator_table;
+static struct msm_actuator msm_piezo_actuator_table;
static struct msm_actuator *actuators[] = {
&msm_vcm_actuator_table,
&msm_piezo_actuator_table,
};
-int32_t msm_actuator_piezo_set_default_focus(
+static int32_t msm_actuator_piezo_set_default_focus(
struct msm_actuator_ctrl_t *a_ctrl,
struct msm_actuator_move_params_t *move_params)
{
int32_t rc = 0;
if (a_ctrl->curr_step_pos != 0) {
- rc = a_ctrl->func_tbl->actuator_i2c_write(a_ctrl,
- a_ctrl->initial_code, 0);
- rc = a_ctrl->func_tbl->actuator_i2c_write(a_ctrl,
- a_ctrl->initial_code, 0);
+ a_ctrl->i2c_tbl_index = 0;
+ rc = a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl,
+ a_ctrl->initial_code, 0, 0);
+ rc = a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl,
+ a_ctrl->initial_code, 0, 0);
+ rc = msm_camera_i2c_write_table_w_microdelay(
+ &a_ctrl->i2c_client, a_ctrl->i2c_reg_tbl,
+ a_ctrl->i2c_tbl_index, a_ctrl->i2c_data_type);
+ if (rc < 0) {
+ pr_err("%s: i2c write error:%d\n",
+ __func__, rc);
+ return rc;
+ }
+ a_ctrl->i2c_tbl_index = 0;
a_ctrl->curr_step_pos = 0;
}
return rc;
}
-int32_t msm_actuator_i2c_write(struct msm_actuator_ctrl_t *a_ctrl,
- int16_t next_lens_position, uint32_t hw_params)
+static int32_t msm_actuator_parse_i2c_params(struct msm_actuator_ctrl_t *a_ctrl,
+ int16_t next_lens_position, uint32_t hw_params, uint16_t delay)
{
struct msm_actuator_reg_params_t *write_arr = a_ctrl->reg_tbl;
uint32_t hw_dword = hw_params;
@@ -70,6 +57,7 @@
uint16_t value = 0;
uint32_t size = a_ctrl->reg_tbl_size, i = 0;
int32_t rc = 0;
+ struct msm_camera_i2c_reg_tbl *i2c_tbl = a_ctrl->i2c_reg_tbl;
CDBG("%s: IN\n", __func__);
for (i = 0; i < size; i++) {
if (write_arr[i].reg_write_type == MSM_ACTUATOR_WRITE_DAC) {
@@ -85,16 +73,13 @@
i2c_byte2 = value & 0xFF;
CDBG("%s: byte1:0x%x, byte2:0x%x\n",
__func__, i2c_byte1, i2c_byte2);
- rc = msm_camera_i2c_write(
- &a_ctrl->i2c_client,
- i2c_byte1, i2c_byte2,
- a_ctrl->i2c_data_type);
- if (rc < 0) {
- pr_err("%s: i2c write error:%d\n",
- __func__, rc);
- return rc;
- }
-
+ i2c_tbl[a_ctrl->i2c_tbl_index].
+ reg_addr = i2c_byte1;
+ i2c_tbl[a_ctrl->i2c_tbl_index].
+ reg_data = i2c_byte2;
+ i2c_tbl[a_ctrl->i2c_tbl_index].
+ delay = 0;
+ a_ctrl->i2c_tbl_index++;
i++;
i2c_byte1 = write_arr[i].reg_addr;
i2c_byte2 = (value & 0xFF00) >> 8;
@@ -110,14 +95,16 @@
}
CDBG("%s: i2c_byte1:0x%x, i2c_byte2:0x%x\n", __func__,
i2c_byte1, i2c_byte2);
- rc = msm_camera_i2c_write(&a_ctrl->i2c_client,
- i2c_byte1, i2c_byte2, a_ctrl->i2c_data_type);
+ i2c_tbl[a_ctrl->i2c_tbl_index].reg_addr = i2c_byte1;
+ i2c_tbl[a_ctrl->i2c_tbl_index].reg_data = i2c_byte2;
+ i2c_tbl[a_ctrl->i2c_tbl_index].delay = delay;
+ a_ctrl->i2c_tbl_index++;
}
CDBG("%s: OUT\n", __func__);
return rc;
}
-int32_t msm_actuator_init_focus(struct msm_actuator_ctrl_t *a_ctrl,
+static int32_t msm_actuator_init_focus(struct msm_actuator_ctrl_t *a_ctrl,
uint16_t size, enum msm_actuator_data_type type,
struct reg_settings_t *settings)
{
@@ -153,7 +140,7 @@
return rc;
}
-int32_t msm_actuator_write_focus(
+static int32_t msm_actuator_write_focus(
struct msm_actuator_ctrl_t *a_ctrl,
uint16_t curr_lens_pos,
struct damping_params_t *damping_params,
@@ -177,27 +164,25 @@
(next_lens_pos +
(sign_direction * damping_code_step))) {
rc = a_ctrl->func_tbl->
- actuator_i2c_write(a_ctrl, next_lens_pos,
- damping_params->hw_params);
+ actuator_parse_i2c_params(a_ctrl, next_lens_pos,
+ damping_params->hw_params, wait_time);
if (rc < 0) {
pr_err("%s: error:%d\n",
__func__, rc);
return rc;
}
curr_lens_pos = next_lens_pos;
- usleep(wait_time);
}
if (curr_lens_pos != code_boundary) {
rc = a_ctrl->func_tbl->
- actuator_i2c_write(a_ctrl, code_boundary,
- damping_params->hw_params);
- usleep(wait_time);
+ actuator_parse_i2c_params(a_ctrl, code_boundary,
+ damping_params->hw_params, wait_time);
}
return rc;
}
-int32_t msm_actuator_piezo_move_focus(
+static int32_t msm_actuator_piezo_move_focus(
struct msm_actuator_ctrl_t *a_ctrl,
struct msm_actuator_move_params_t *move_params)
{
@@ -208,17 +193,27 @@
if (num_steps == 0)
return rc;
+ a_ctrl->i2c_tbl_index = 0;
rc = a_ctrl->func_tbl->
- actuator_i2c_write(a_ctrl,
+ actuator_parse_i2c_params(a_ctrl,
(num_steps *
a_ctrl->region_params[0].code_per_step),
- move_params->ringing_params[0].hw_params);
+ move_params->ringing_params[0].hw_params, 0);
+ rc = msm_camera_i2c_write_table_w_microdelay(&a_ctrl->i2c_client,
+ a_ctrl->i2c_reg_tbl, a_ctrl->i2c_tbl_index,
+ a_ctrl->i2c_data_type);
+ if (rc < 0) {
+ pr_err("%s: i2c write error:%d\n",
+ __func__, rc);
+ return rc;
+ }
+ a_ctrl->i2c_tbl_index = 0;
a_ctrl->curr_step_pos = dest_step_position;
return rc;
}
-int32_t msm_actuator_move_focus(
+static int32_t msm_actuator_move_focus(
struct msm_actuator_ctrl_t *a_ctrl,
struct msm_actuator_move_params_t *move_params)
{
@@ -241,6 +236,7 @@
return rc;
curr_lens_pos = a_ctrl->step_position_table[a_ctrl->curr_step_pos];
+ a_ctrl->i2c_tbl_index = 0;
CDBG("curr_step_pos =%d dest_step_pos =%d curr_lens_pos=%d\n",
a_ctrl->curr_step_pos, dest_step_pos, curr_lens_pos);
@@ -299,10 +295,20 @@
a_ctrl->curr_step_pos = target_step_pos;
}
+ rc = msm_camera_i2c_write_table_w_microdelay(&a_ctrl->i2c_client,
+ a_ctrl->i2c_reg_tbl, a_ctrl->i2c_tbl_index,
+ a_ctrl->i2c_data_type);
+ if (rc < 0) {
+ pr_err("%s: i2c write error:%d\n",
+ __func__, rc);
+ return rc;
+ }
+ a_ctrl->i2c_tbl_index = 0;
+
return rc;
}
-int32_t msm_actuator_init_step_table(struct msm_actuator_ctrl_t *a_ctrl,
+static int32_t msm_actuator_init_step_table(struct msm_actuator_ctrl_t *a_ctrl,
struct msm_actuator_set_info_t *set_info)
{
int16_t code_per_step = 0;
@@ -361,7 +367,7 @@
return rc;
}
-int32_t msm_actuator_set_default_focus(
+static int32_t msm_actuator_set_default_focus(
struct msm_actuator_ctrl_t *a_ctrl,
struct msm_actuator_move_params_t *move_params)
{
@@ -373,7 +379,7 @@
return rc;
}
-int32_t msm_actuator_power_down(struct msm_actuator_ctrl_t *a_ctrl)
+static int32_t msm_actuator_power_down(struct msm_actuator_ctrl_t *a_ctrl)
{
int32_t rc = 0;
if (a_ctrl->vcm_enable) {
@@ -384,10 +390,13 @@
kfree(a_ctrl->step_position_table);
a_ctrl->step_position_table = NULL;
+ kfree(a_ctrl->i2c_reg_tbl);
+ a_ctrl->i2c_reg_tbl = NULL;
+ a_ctrl->i2c_tbl_index = 0;
return rc;
}
-int32_t msm_actuator_init(struct msm_actuator_ctrl_t *a_ctrl,
+static int32_t msm_actuator_init(struct msm_actuator_ctrl_t *a_ctrl,
struct msm_actuator_set_info_t *set_info) {
struct reg_settings_t *init_settings = NULL;
int32_t rc = -EFAULT;
@@ -412,7 +421,6 @@
pr_err("%s: MAX_ACTUATOR_REGION is exceeded.\n", __func__);
return -EFAULT;
}
- a_ctrl->total_steps = set_info->af_tuning_params.total_steps;
a_ctrl->pwd_step = set_info->af_tuning_params.pwd_step;
a_ctrl->total_steps = set_info->af_tuning_params.total_steps;
@@ -430,11 +438,22 @@
__func__);
return -EFAULT;
}
+
+ a_ctrl->i2c_reg_tbl =
+ kmalloc(sizeof(struct msm_camera_i2c_reg_tbl) *
+ (set_info->af_tuning_params.total_steps + 1), GFP_KERNEL);
+ if (!a_ctrl->i2c_reg_tbl) {
+ pr_err("%s kmalloc fail\n", __func__);
+ return -EFAULT;
+ }
+
if (copy_from_user(&a_ctrl->reg_tbl,
(void *)set_info->actuator_params.reg_tbl_params,
a_ctrl->reg_tbl_size *
- sizeof(struct msm_actuator_reg_params_t)))
+ sizeof(struct msm_actuator_reg_params_t))) {
+ kfree(a_ctrl->i2c_reg_tbl);
return -EFAULT;
+ }
if (set_info->actuator_params.init_setting_size) {
if (a_ctrl->func_tbl->actuator_init_focus) {
@@ -442,6 +461,7 @@
(set_info->actuator_params.init_setting_size),
GFP_KERNEL);
if (init_settings == NULL) {
+ kfree(a_ctrl->i2c_reg_tbl);
pr_err("%s Error allocating memory for init_settings\n",
__func__);
return -EFAULT;
@@ -451,6 +471,7 @@
set_info->actuator_params.init_setting_size *
sizeof(struct reg_settings_t))) {
kfree(init_settings);
+ kfree(a_ctrl->i2c_reg_tbl);
pr_err("%s Error copying init_settings\n",
__func__);
return -EFAULT;
@@ -461,6 +482,7 @@
init_settings);
kfree(init_settings);
if (rc < 0) {
+ kfree(a_ctrl->i2c_reg_tbl);
pr_err("%s Error actuator_init_focus\n",
__func__);
return -EFAULT;
@@ -480,7 +502,7 @@
}
-int32_t msm_actuator_config(struct msm_actuator_ctrl_t *a_ctrl,
+static int32_t msm_actuator_config(struct msm_actuator_ctrl_t *a_ctrl,
void __user *argp)
{
struct msm_actuator_cfg_data cdata;
@@ -519,7 +541,7 @@
return rc;
}
-int32_t msm_actuator_i2c_probe(
+static int32_t msm_actuator_i2c_probe(
struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -554,7 +576,7 @@
return rc;
}
-int32_t msm_actuator_power_up(struct msm_actuator_ctrl_t *a_ctrl)
+static int32_t msm_actuator_power_up(struct msm_actuator_ctrl_t *a_ctrl)
{
int rc = 0;
CDBG("%s called\n", __func__);
@@ -594,7 +616,7 @@
return i2c_add_driver(msm_actuator_t.i2c_driver);
}
-long msm_actuator_subdev_ioctl(struct v4l2_subdev *sd,
+static long msm_actuator_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg)
{
struct msm_actuator_ctrl_t *a_ctrl = get_actrl(sd);
@@ -607,7 +629,7 @@
}
}
-int32_t msm_actuator_power(struct v4l2_subdev *sd, int on)
+static int32_t msm_actuator_power(struct v4l2_subdev *sd, int on)
{
int rc = 0;
struct msm_actuator_ctrl_t *a_ctrl = get_actrl(sd);
@@ -644,6 +666,31 @@
};
+static struct msm_actuator msm_vcm_actuator_table = {
+ .act_type = ACTUATOR_VCM,
+ .func_tbl = {
+ .actuator_init_step_table = msm_actuator_init_step_table,
+ .actuator_move_focus = msm_actuator_move_focus,
+ .actuator_write_focus = msm_actuator_write_focus,
+ .actuator_set_default_focus = msm_actuator_set_default_focus,
+ .actuator_init_focus = msm_actuator_init_focus,
+ .actuator_parse_i2c_params = msm_actuator_parse_i2c_params,
+ },
+};
+
+static struct msm_actuator msm_piezo_actuator_table = {
+ .act_type = ACTUATOR_PIEZO,
+ .func_tbl = {
+ .actuator_init_step_table = NULL,
+ .actuator_move_focus = msm_actuator_piezo_move_focus,
+ .actuator_write_focus = NULL,
+ .actuator_set_default_focus =
+ msm_actuator_piezo_set_default_focus,
+ .actuator_init_focus = msm_actuator_init_focus,
+ .actuator_parse_i2c_params = msm_actuator_parse_i2c_params,
+ },
+};
+
subsys_initcall(msm_actuator_i2c_add_driver);
MODULE_DESCRIPTION("MSM ACTUATOR");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/actuators/msm_actuator.h b/drivers/media/video/msm/actuators/msm_actuator.h
index 4f936e7..82157e8 100644
--- a/drivers/media/video/msm/actuators/msm_actuator.h
+++ b/drivers/media/video/msm/actuators/msm_actuator.h
@@ -51,8 +51,8 @@
struct msm_actuator_move_params_t *);
int32_t (*actuator_move_focus) (struct msm_actuator_ctrl_t *,
struct msm_actuator_move_params_t *);
- int32_t (*actuator_i2c_write)(struct msm_actuator_ctrl_t *,
- int16_t, uint32_t);
+ int32_t (*actuator_parse_i2c_params)(struct msm_actuator_ctrl_t *,
+ int16_t, uint32_t, uint16_t);
int32_t (*actuator_write_focus)(struct msm_actuator_ctrl_t *,
uint16_t,
struct damping_params_t *,
@@ -87,40 +87,11 @@
uint32_t total_steps;
uint16_t pwd_step;
uint16_t initial_code;
+ struct msm_camera_i2c_reg_tbl *i2c_reg_tbl;
+ uint16_t i2c_tbl_index;
};
struct msm_actuator_ctrl_t *get_actrl(struct v4l2_subdev *sd);
-int32_t msm_actuator_i2c_write(struct msm_actuator_ctrl_t *a_ctrl,
- int16_t next_lens_position, uint32_t hw_params);
-int32_t msm_actuator_init_focus(struct msm_actuator_ctrl_t *a_ctrl,
- uint16_t size, enum msm_actuator_data_type type,
- struct reg_settings_t *settings);
-int32_t msm_actuator_i2c_write_b_af(struct msm_actuator_ctrl_t *a_ctrl,
- uint8_t msb,
- uint8_t lsb);
-int32_t msm_actuator_move_focus(struct msm_actuator_ctrl_t *a_ctrl,
- struct msm_actuator_move_params_t *move_params);
-int32_t msm_actuator_piezo_move_focus(
- struct msm_actuator_ctrl_t *a_ctrl,
- struct msm_actuator_move_params_t *move_params);
-int32_t msm_actuator_init_step_table(struct msm_actuator_ctrl_t *a_ctrl,
- struct msm_actuator_set_info_t *set_info);
-int32_t msm_actuator_set_default_focus(struct msm_actuator_ctrl_t *a_ctrl,
- struct msm_actuator_move_params_t *move_params);
-int32_t msm_actuator_piezo_set_default_focus(
- struct msm_actuator_ctrl_t *a_ctrl,
- struct msm_actuator_move_params_t *move_params);
-int32_t msm_actuator_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id);
-int32_t msm_actuator_write_focus(struct msm_actuator_ctrl_t *a_ctrl,
- uint16_t curr_lens_pos, struct damping_params_t *damping_params,
- int8_t sign_direction, int16_t code_boundary);
-int32_t msm_actuator_write_focus2(struct msm_actuator_ctrl_t *a_ctrl,
- uint16_t curr_lens_pos, struct damping_params_t *damping_params,
- int8_t sign_direction, int16_t code_boundary);
-long msm_actuator_subdev_ioctl(struct v4l2_subdev *sd,
- unsigned int cmd, void *arg);
-int32_t msm_actuator_power(struct v4l2_subdev *sd, int on);
#define VIDIOC_MSM_ACTUATOR_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE + 11, void __user *)
diff --git a/drivers/media/video/msm/cpp/Makefile b/drivers/media/video/msm/cpp/Makefile
new file mode 100644
index 0000000..b4f1fdf
--- /dev/null
+++ b/drivers/media/video/msm/cpp/Makefile
@@ -0,0 +1,5 @@
+GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
+ccflags-y += -Idrivers/media/video/msm
+ccflags-y += -Idrivers/media/video/msm/io
+obj-$(CONFIG_MSM_CPP) += msm_cpp.o
+
diff --git a/drivers/media/video/msm/cpp/msm_cpp.c b/drivers/media/video/msm/cpp/msm_cpp.c
new file mode 100644
index 0000000..e569388
--- /dev/null
+++ b/drivers/media/video/msm/cpp/msm_cpp.c
@@ -0,0 +1,412 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <mach/board.h>
+#include <mach/camera.h>
+#include <mach/vreg.h>
+#include <media/msm_isp.h>
+#include <linux/proc_fs.h>
+#include <linux/debugfs.h>
+
+#include "msm_cpp.h"
+#include "msm.h"
+
+#define CONFIG_MSM_CPP_DBG 0
+
+#if CONFIG_MSM_CPP_DBG
+#define CPP_DBG(fmt, args...) pr_info(fmt, ##args)
+#else
+#define CPP_DBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ uint32_t i;
+ struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
+ CPP_DBG("%s\n", __func__);
+
+ mutex_lock(&cpp_dev->mutex);
+ if (cpp_dev->cpp_open_cnt == MAX_ACTIVE_CPP_INSTANCE) {
+ pr_err("No free CPP instance\n");
+ mutex_unlock(&cpp_dev->mutex);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) {
+ if (cpp_dev->cpp_subscribe_list[i].active == 0) {
+ cpp_dev->cpp_subscribe_list[i].active = 1;
+ cpp_dev->cpp_subscribe_list[i].vfh = &fh->vfh;
+ break;
+ }
+ }
+ if (i == MAX_ACTIVE_CPP_INSTANCE) {
+ pr_err("No free instance\n");
+ mutex_unlock(&cpp_dev->mutex);
+ return -ENODEV;
+ }
+
+ CPP_DBG("open %d %p\n", i, &fh->vfh);
+ cpp_dev->cpp_open_cnt++;
+ mutex_unlock(&cpp_dev->mutex);
+ return 0;
+}
+
+static int cpp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ uint32_t i;
+ struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
+ mutex_lock(&cpp_dev->mutex);
+ for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) {
+ if (cpp_dev->cpp_subscribe_list[i].vfh == &fh->vfh) {
+ cpp_dev->cpp_subscribe_list[i].active = 0;
+ cpp_dev->cpp_subscribe_list[i].vfh = NULL;
+ break;
+ }
+ }
+ if (i == MAX_ACTIVE_CPP_INSTANCE) {
+ pr_err("Invalid close\n");
+ mutex_unlock(&cpp_dev->mutex);
+ return -ENODEV;
+ }
+
+ CPP_DBG("close %d %p\n", i, &fh->vfh);
+ cpp_dev->cpp_open_cnt--;
+ mutex_unlock(&cpp_dev->mutex);
+ return 0;
+}
+
+static const struct v4l2_subdev_internal_ops msm_cpp_internal_ops = {
+ .open = cpp_open_node,
+ .close = cpp_close_node,
+};
+
+static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev)
+{
+ struct v4l2_event v4l2_evt;
+ struct msm_queue_cmd *frame_qcmd;
+ struct msm_queue_cmd *event_qcmd;
+ struct msm_cpp_frame_info_t *processed_frame;
+ struct msm_device_queue *queue = &cpp_dev->processing_q;
+
+ if (queue->len > 0) {
+ frame_qcmd = msm_dequeue(queue, list_frame);
+ processed_frame = frame_qcmd->command;
+
+ event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
+ if (!event_qcmd) {
+ pr_err("%s Insufficient memory. return", __func__);
+ return -ENOMEM;
+ }
+ atomic_set(&event_qcmd->on_heap, 1);
+ event_qcmd->command = processed_frame;
+ CPP_DBG("fid %d\n", processed_frame->frame_id);
+ msm_enqueue(&cpp_dev->eventData_q, &event_qcmd->list_eventdata);
+
+ v4l2_evt.id = processed_frame->inst_id;
+ v4l2_evt.type = V4L2_EVENT_CPP_FRAME_DONE;
+ v4l2_event_queue(cpp_dev->subdev.devnode, &v4l2_evt);
+ }
+ return 0;
+}
+
+static int msm_cpp_send_frame_to_hardware(struct cpp_device *cpp_dev)
+{
+ struct msm_queue_cmd *frame_qcmd;
+ struct msm_cpp_frame_info_t *process_frame;
+ struct msm_device_queue *queue;
+
+ if (cpp_dev->processing_q.len < MAX_CPP_PROCESSING_FRAME) {
+ while (cpp_dev->processing_q.len < MAX_CPP_PROCESSING_FRAME) {
+ if (cpp_dev->realtime_q.len != 0) {
+ queue = &cpp_dev->realtime_q;
+ } else if (cpp_dev->offline_q.len != 0) {
+ queue = &cpp_dev->offline_q;
+ } else {
+ pr_debug("%s: All frames queued\n", __func__);
+ break;
+ }
+ frame_qcmd = msm_dequeue(queue, list_frame);
+ /*TBD Code to actually sending to harware*/
+ process_frame = frame_qcmd->command;
+
+ msm_enqueue(&cpp_dev->processing_q,
+ &frame_qcmd->list_frame);
+ }
+ }
+ return 0;
+}
+
+long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg)
+{
+ struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
+ struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
+ int rc = 0;
+
+ CPP_DBG("%s: %d\n", __func__, __LINE__);
+ mutex_lock(&cpp_dev->mutex);
+ CPP_DBG("%s cmd: %d\n", __func__, cmd);
+ switch (cmd) {
+ case VIDIOC_MSM_CPP_CFG: {
+ struct msm_queue_cmd *frame_qcmd;
+ struct msm_cpp_frame_info_t *new_frame =
+ kzalloc(sizeof(struct msm_cpp_frame_info_t),
+ GFP_KERNEL);
+ if (!new_frame) {
+ pr_err("%s Insufficient memory. return", __func__);
+ mutex_unlock(&cpp_dev->mutex);
+ return -ENOMEM;
+ }
+
+ COPY_FROM_USER(rc, new_frame,
+ (void __user *)ioctl_ptr->ioctl_ptr,
+ sizeof(struct msm_cpp_frame_info_t));
+ if (rc) {
+ ERR_COPY_FROM_USER();
+ kfree(new_frame);
+ mutex_unlock(&cpp_dev->mutex);
+ return -EINVAL;
+ }
+
+ frame_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
+ if (!frame_qcmd) {
+ pr_err("%s Insufficient memory. return", __func__);
+ kfree(new_frame);
+ mutex_unlock(&cpp_dev->mutex);
+ return -ENOMEM;
+ }
+
+ atomic_set(&frame_qcmd->on_heap, 1);
+ frame_qcmd->command = new_frame;
+ if (new_frame->frame_type == MSM_CPP_REALTIME_FRAME) {
+ msm_enqueue(&cpp_dev->realtime_q,
+ &frame_qcmd->list_frame);
+ } else if (new_frame->frame_type == MSM_CPP_OFFLINE_FRAME) {
+ msm_enqueue(&cpp_dev->offline_q,
+ &frame_qcmd->list_frame);
+ } else {
+ pr_err("%s: Invalid frame type\n", __func__);
+ kfree(new_frame);
+ kfree(frame_qcmd);
+ mutex_unlock(&cpp_dev->mutex);
+ return -EINVAL;
+ }
+ break;
+ }
+ case VIDIOC_MSM_CPP_GET_EVENTPAYLOAD: {
+ struct msm_device_queue *queue = &cpp_dev->eventData_q;
+ struct msm_queue_cmd *event_qcmd;
+ struct msm_cpp_frame_info_t *process_frame;
+ event_qcmd = msm_dequeue(queue, list_eventdata);
+ process_frame = event_qcmd->command;
+ CPP_DBG("fid %d\n", process_frame->frame_id);
+ if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
+ process_frame,
+ sizeof(struct msm_cpp_frame_info_t))) {
+ mutex_unlock(&cpp_dev->mutex);
+ return -EINVAL;
+ }
+ kfree(process_frame);
+ kfree(event_qcmd);
+ break;
+ }
+ }
+ mutex_unlock(&cpp_dev->mutex);
+ CPP_DBG("%s: %d\n", __func__, __LINE__);
+ return 0;
+}
+
+int msm_cpp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ CPP_DBG("%s\n", __func__);
+ return v4l2_event_subscribe(fh, sub, MAX_CPP_V4l2_EVENTS);
+}
+
+int msm_cpp_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ CPP_DBG("%s\n", __func__);
+ return v4l2_event_unsubscribe(fh, sub);
+}
+
+static struct v4l2_subdev_core_ops msm_cpp_subdev_core_ops = {
+ .ioctl = msm_cpp_subdev_ioctl,
+ .subscribe_event = msm_cpp_subscribe_event,
+ .unsubscribe_event = msm_cpp_unsubscribe_event,
+};
+
+static const struct v4l2_subdev_ops msm_cpp_subdev_ops = {
+ .core = &msm_cpp_subdev_core_ops,
+};
+
+static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev);
+
+static struct v4l2_file_operations msm_cpp_v4l2_subdev_fops;
+
+static long msm_cpp_subdev_do_ioctl(
+ struct file *file, unsigned int cmd, void *arg)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+ struct v4l2_fh *vfh = file->private_data;
+
+ switch (cmd) {
+ case VIDIOC_DQEVENT:
+ if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
+ return -ENOIOCTLCMD;
+
+ return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK);
+
+ case VIDIOC_SUBSCRIBE_EVENT:
+ return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
+
+ case VIDIOC_UNSUBSCRIBE_EVENT:
+ return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
+
+ case VIDIOC_MSM_CPP_GET_INST_INFO: {
+ uint32_t i;
+ struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
+ struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
+ struct msm_cpp_frame_info_t inst_info;
+ for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) {
+ if (cpp_dev->cpp_subscribe_list[i].vfh == vfh) {
+ inst_info.inst_id = i;
+ break;
+ }
+ }
+ if (copy_to_user(
+ (void __user *)ioctl_ptr->ioctl_ptr, &inst_info,
+ sizeof(struct msm_cpp_frame_info_t))) {
+ return -EINVAL;
+ }
+ }
+ break;
+ default:
+ return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
+ }
+
+ return 0;
+}
+
+static long msm_cpp_subdev_fops_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return video_usercopy(file, cmd, arg, msm_cpp_subdev_do_ioctl);
+}
+
+static int __devinit cpp_probe(struct platform_device *pdev)
+{
+ struct cpp_device *cpp_dev;
+ struct msm_cam_subdev_info sd_info;
+ int rc = 0;
+ CDBG("%s: device id = %d\n", __func__, pdev->id);
+ cpp_dev = kzalloc(sizeof(struct cpp_device), GFP_KERNEL);
+ if (!cpp_dev) {
+ pr_err("%s: no enough memory\n", __func__);
+ return -ENOMEM;
+ }
+ v4l2_subdev_init(&cpp_dev->subdev, &msm_cpp_subdev_ops);
+ cpp_dev->subdev.internal_ops = &msm_cpp_internal_ops;
+ snprintf(cpp_dev->subdev.name, ARRAY_SIZE(cpp_dev->subdev.name),
+ "cpp");
+ cpp_dev->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ cpp_dev->subdev.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
+ v4l2_set_subdevdata(&cpp_dev->subdev, cpp_dev);
+ platform_set_drvdata(pdev, &cpp_dev->subdev);
+ mutex_init(&cpp_dev->mutex);
+
+ cpp_dev->pdev = pdev;
+
+ media_entity_init(&cpp_dev->subdev.entity, 0, NULL, 0);
+ cpp_dev->subdev.entity.type = MEDIA_ENT_T_DEVNODE_V4L;
+ cpp_dev->subdev.entity.group_id = CPP_DEV;
+ cpp_dev->subdev.entity.name = pdev->name;
+ sd_info.sdev_type = CPP_DEV;
+ sd_info.sd_index = pdev->id;
+ msm_cam_register_subdev_node(&cpp_dev->subdev, &sd_info);
+ msm_cpp_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner;
+ msm_cpp_v4l2_subdev_fops.open = v4l2_subdev_fops.open;
+ msm_cpp_v4l2_subdev_fops.unlocked_ioctl = msm_cpp_subdev_fops_ioctl;
+ msm_cpp_v4l2_subdev_fops.release = v4l2_subdev_fops.release;
+ msm_cpp_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll;
+
+ cpp_dev->subdev.devnode->fops = &msm_cpp_v4l2_subdev_fops;
+ cpp_dev->subdev.entity.revision = cpp_dev->subdev.devnode->num;
+ msm_cpp_enable_debugfs(cpp_dev);
+ msm_queue_init(&cpp_dev->eventData_q, "eventdata");
+ msm_queue_init(&cpp_dev->offline_q, "frame");
+ msm_queue_init(&cpp_dev->realtime_q, "frame");
+ msm_queue_init(&cpp_dev->processing_q, "frame");
+ cpp_dev->cpp_open_cnt = 0;
+
+ return rc;
+}
+
+static struct platform_driver cpp_driver = {
+ .probe = cpp_probe,
+ .driver = {
+ .name = MSM_CPP_DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_cpp_init_module(void)
+{
+ return platform_driver_register(&cpp_driver);
+}
+
+static void __exit msm_cpp_exit_module(void)
+{
+ platform_driver_unregister(&cpp_driver);
+}
+
+static int msm_cpp_debugfs_stream_s(void *data, u64 val)
+{
+ struct cpp_device *cpp_dev = data;
+ CPP_DBG("CPP processing frame E\n");
+ while (1) {
+ mutex_lock(&cpp_dev->mutex);
+ msm_cpp_notify_frame_done(cpp_dev);
+ msm_cpp_send_frame_to_hardware(cpp_dev);
+ mutex_unlock(&cpp_dev->mutex);
+ msleep(20);
+ }
+ CPP_DBG("CPP processing frame X\n");
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(cpp_debugfs_stream, NULL,
+ msm_cpp_debugfs_stream_s, "%llu\n");
+
+static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev)
+{
+ struct dentry *debugfs_base;
+ debugfs_base = debugfs_create_dir("msm_camera", NULL);
+ if (!debugfs_base)
+ return -ENOMEM;
+
+ if (!debugfs_create_file("test", S_IRUGO | S_IWUSR, debugfs_base,
+ (void *)cpp_dev, &cpp_debugfs_stream))
+ return -ENOMEM;
+
+ return 0;
+}
+
+module_init(msm_cpp_init_module);
+module_exit(msm_cpp_exit_module);
+MODULE_DESCRIPTION("MSM CPP driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/cpp/msm_cpp.h b/drivers/media/video/msm/cpp/msm_cpp.h
new file mode 100644
index 0000000..8c10cac
--- /dev/null
+++ b/drivers/media/video/msm/cpp/msm_cpp.h
@@ -0,0 +1,65 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <media/v4l2-subdev.h>
+
+#define MAX_ACTIVE_CPP_INSTANCE 8
+#define MAX_CPP_PROCESSING_FRAME 2
+#define MAX_CPP_V4l2_EVENTS 30
+
+#define MSM_CPP_MICRO_BASE 0x4000
+#define MSM_CPP_MICRO_HW_VERSION 0x0000
+#define MSM_CPP_MICRO_IRQGEN_STAT 0x0004
+#define MSM_CPP_MICRO_IRQGEN_CLR 0x0008
+#define MSM_CPP_MICRO_IRQGEN_MASK 0x000C
+#define MSM_CPP_MICRO_FIFO_TX_DATA 0x0010
+#define MSM_CPP_MICRO_FIFO_TX_STAT 0x0014
+#define MSM_CPP_MICRO_FIFO_RX_DATA 0x0018
+#define MSM_CPP_MICRO_FIFO_RX_STAT 0x001C
+#define MSM_CPP_MICRO_BOOT_START 0x0020
+#define MSM_CPP_MICRO_BOOT_LDORG 0x0024
+#define MSM_CPP_MICRO_CLKEN_CTL 0x0030
+
+struct cpp_subscribe_info {
+ struct v4l2_fh *vfh;
+ uint32_t active;
+};
+
+struct cpp_device {
+ struct platform_device *pdev;
+ struct v4l2_subdev subdev;
+ struct resource *mem;
+ struct resource *irq;
+ struct resource *io;
+ void __iomem *base;
+ struct clk *cpp_clk[2];
+ struct mutex mutex;
+
+ struct cpp_subscribe_info cpp_subscribe_list[MAX_ACTIVE_CPP_INSTANCE];
+ uint32_t cpp_open_cnt;
+
+ struct msm_device_queue eventData_q; /*V4L2 Event Payload Queue*/
+
+ /*Offline Frame Queue
+ process when realtime queue is empty*/
+ struct msm_device_queue offline_q;
+ /*Realtime Frame Queue
+ process with highest priority*/
+ struct msm_device_queue realtime_q;
+ /*Processing Queue
+ store frame info for frames sent to microcontroller*/
+ struct msm_device_queue processing_q;
+};
+
diff --git a/drivers/media/video/msm/io/msm_camera_i2c.c b/drivers/media/video/msm/io/msm_camera_i2c.c
index cecf9b0..e946569 100644
--- a/drivers/media/video/msm/io/msm_camera_i2c.c
+++ b/drivers/media/video/msm/io/msm_camera_i2c.c
@@ -267,6 +267,35 @@
return rc;
}
+int32_t msm_camera_i2c_write_table_w_microdelay(
+ struct msm_camera_i2c_client *client,
+ struct msm_camera_i2c_reg_tbl *reg_tbl, uint16_t size,
+ enum msm_camera_i2c_data_type data_type)
+{
+ int i;
+ int32_t rc = -EFAULT;
+
+ if (!client || !reg_tbl)
+ return rc;
+
+ if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
+ && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
+ || (data_type != MSM_CAMERA_I2C_BYTE_DATA
+ && data_type != MSM_CAMERA_I2C_WORD_DATA))
+ return rc;
+
+ for (i = 0; i < size; i++) {
+ rc = msm_camera_i2c_write(client, reg_tbl->reg_addr,
+ reg_tbl->reg_data, data_type);
+ if (rc < 0)
+ break;
+ if (reg_tbl->delay)
+ usleep_range(reg_tbl->delay, reg_tbl->delay + 1000);
+ reg_tbl++;
+ }
+ return rc;
+}
+
int32_t msm_camera_i2c_write_tbl(struct msm_camera_i2c_client *client,
struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size,
enum msm_camera_i2c_data_type data_type)
diff --git a/drivers/media/video/msm/io/msm_camera_i2c.h b/drivers/media/video/msm/io/msm_camera_i2c.h
index 01c8259..a0cdd77 100644
--- a/drivers/media/video/msm/io/msm_camera_i2c.h
+++ b/drivers/media/video/msm/io/msm_camera_i2c.h
@@ -58,6 +58,12 @@
enum msm_camera_i2c_cmd_type cmd_type;
};
+struct msm_camera_i2c_reg_tbl {
+ uint16_t reg_addr;
+ uint16_t reg_data;
+ uint16_t delay;
+};
+
struct msm_camera_i2c_conf_array {
struct msm_camera_i2c_reg_conf *conf;
uint16_t size;
@@ -107,6 +113,11 @@
uint16_t addr, uint16_t data,
enum msm_camera_i2c_data_type data_type);
+int32_t msm_camera_i2c_write_table_w_microdelay(
+ struct msm_camera_i2c_client *client,
+ struct msm_camera_i2c_reg_tbl *reg_tbl, uint16_t size,
+ enum msm_camera_i2c_data_type data_type);
+
int32_t msm_camera_i2c_write_tbl(struct msm_camera_i2c_client *client,
struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size,
enum msm_camera_i2c_data_type data_type);
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index d34b8e1..c6fadc0 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -166,17 +166,22 @@
struct msm_cam_v4l2_dev_inst, eventHandle);
D("%s\n", __func__);
WARN_ON(pctx != f->private_data);
+
+ mutex_lock(&pcam_inst->inst_lock);
rc = vb2_reqbufs(&pcam_inst->vid_bufq, pb);
if (rc < 0) {
pr_err("%s reqbufs failed %d ", __func__, rc);
+ mutex_unlock(&pcam_inst->inst_lock);
return rc;
}
if (!pb->count) {
/* Deallocation. free buf_offset array */
D("%s Inst %p freeing buffer offsets array",
__func__, pcam_inst);
- for (j = 0 ; j < pcam_inst->buf_count ; j++)
+ for (j = 0 ; j < pcam_inst->buf_count ; j++) {
kfree(pcam_inst->buf_offset[j]);
+ pcam_inst->buf_offset[j] = NULL;
+ }
kfree(pcam_inst->buf_offset);
pcam_inst->buf_offset = NULL;
/* If the userspace has deallocated all the
@@ -194,6 +199,7 @@
GFP_KERNEL);
if (!pcam_inst->buf_offset) {
pr_err("%s out of memory ", __func__);
+ mutex_unlock(&pcam_inst->inst_lock);
return -ENOMEM;
}
for (i = 0; i < pb->count; i++) {
@@ -202,15 +208,19 @@
pcam_inst->plane_info.num_planes, GFP_KERNEL);
if (!pcam_inst->buf_offset[i]) {
pr_err("%s out of memory ", __func__);
- for (j = i-1 ; j >= 0; j--)
+ for (j = i-1 ; j >= 0; j--) {
kfree(pcam_inst->buf_offset[j]);
+ pcam_inst->buf_offset[j] = NULL;
+ }
kfree(pcam_inst->buf_offset);
pcam_inst->buf_offset = NULL;
+ mutex_unlock(&pcam_inst->inst_lock);
return -ENOMEM;
}
}
}
pcam_inst->buf_count = pb->count;
+ mutex_unlock(&pcam_inst->inst_lock);
return rc;
}
@@ -218,13 +228,17 @@
struct v4l2_buffer *pb)
{
/* get the video device */
+ int rc = 0;
struct msm_cam_v4l2_dev_inst *pcam_inst;
pcam_inst = container_of(f->private_data,
struct msm_cam_v4l2_dev_inst, eventHandle);
D("%s\n", __func__);
WARN_ON(pctx != f->private_data);
- return vb2_querybuf(&pcam_inst->vid_bufq, pb);
+ mutex_lock(&pcam_inst->inst_lock);
+ rc = vb2_querybuf(&pcam_inst->vid_bufq, pb);
+ mutex_unlock(&pcam_inst->inst_lock);
+ return rc;
}
static int msm_camera_v4l2_qbuf(struct file *f, void *pctx,
@@ -240,8 +254,10 @@
pcam_inst->image_mode, pb->index);
WARN_ON(pctx != f->private_data);
+ mutex_lock(&pcam_inst->inst_lock);
if (!pcam_inst->buf_offset) {
pr_err("%s Buffer is already released. Returning.\n", __func__);
+ mutex_unlock(&pcam_inst->inst_lock);
return -EINVAL;
}
@@ -249,6 +265,7 @@
/* Reject the buffer if planes array was not allocated */
if (pb->m.planes == NULL) {
pr_err("%s Planes array is null\n", __func__);
+ mutex_unlock(&pcam_inst->inst_lock);
return -EINVAL;
}
for (i = 0; i < pcam_inst->plane_info.num_planes; i++) {
@@ -269,7 +286,7 @@
rc = vb2_qbuf(&pcam_inst->vid_bufq, pb);
D("%s, videobuf_qbuf mode %d and idx %d returns %d\n", __func__,
pcam_inst->image_mode, pb->index, rc);
-
+ mutex_unlock(&pcam_inst->inst_lock);
return rc;
}
@@ -285,6 +302,11 @@
D("%s\n", __func__);
WARN_ON(pctx != f->private_data);
+ mutex_lock(&pcam_inst->inst_lock);
+ if (0 == pcam_inst->streamon) {
+ mutex_unlock(&pcam_inst->inst_lock);
+ return -EACCES;
+ }
rc = vb2_dqbuf(&pcam_inst->vid_bufq, pb, f->f_flags & O_NONBLOCK);
D("%s, videobuf_dqbuf returns %d\n", __func__, rc);
@@ -292,6 +314,7 @@
/* Reject the buffer if planes array was not allocated */
if (pb->m.planes == NULL) {
pr_err("%s Planes array is null\n", __func__);
+ mutex_unlock(&pcam_inst->inst_lock);
return -EINVAL;
}
for (i = 0; i < pcam_inst->plane_info.num_planes; i++) {
@@ -309,6 +332,7 @@
pb->reserved = pcam_inst->buf_offset[pb->index][0].addr_offset;
}
+ mutex_unlock(&pcam_inst->inst_lock);
return rc;
}
@@ -325,9 +349,13 @@
D("%s Inst %p\n", __func__, pcam_inst);
WARN_ON(pctx != f->private_data);
+ mutex_lock(&pcam->vid_lock);
+ mutex_lock(&pcam_inst->inst_lock);
if ((buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
(buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
pr_err("%s Invalid buffer type ", __func__);
+ mutex_unlock(&pcam_inst->inst_lock);
+ mutex_unlock(&pcam->vid_lock);
return -EINVAL;
}
@@ -336,10 +364,10 @@
rc = vb2_streamon(&pcam_inst->vid_bufq, buf_type);
D("%s, videobuf_streamon returns %d\n", __func__, rc);
- mutex_lock(&pcam->vid_lock);
/* turn HW (VFE/sensor) streaming */
pcam_inst->streamon = 1;
rc = msm_server_streamon(pcam, pcam_inst->my_index);
+ mutex_unlock(&pcam_inst->inst_lock);
mutex_unlock(&pcam->vid_lock);
D("%s rc = %d\n", __func__, rc);
return rc;
@@ -367,16 +395,20 @@
/* first turn of HW (VFE/sensor) streaming so that buffers are
not in use when we free the buffers */
mutex_lock(&pcam->vid_lock);
+ mutex_lock(&pcam_inst->inst_lock);
pcam_inst->streamon = 0;
if (msm_server_get_usecount() > 0)
rc = msm_server_streamoff(pcam, pcam_inst->my_index);
- mutex_unlock(&pcam->vid_lock);
+
if (rc < 0)
pr_err("%s: hw failed to stop streaming\n", __func__);
/* stop buffer streaming */
rc = vb2_streamoff(&pcam_inst->vid_bufq, buf_type);
D("%s, videobuf_streamoff returns %d\n", __func__, rc);
+
+ mutex_unlock(&pcam_inst->inst_lock);
+ mutex_unlock(&pcam->vid_lock);
return rc;
}
@@ -466,11 +498,13 @@
D("%s\n", __func__);
WARN_ON(pctx != f->private_data);
+ mutex_lock(&pcam->vid_lock);
rc = msm_server_try_fmt(pcam, pfmt);
if (rc)
pr_err("Format %x not found, rc = %d\n",
pfmt->fmt.pix.pixelformat, rc);
+ mutex_unlock(&pcam->vid_lock);
return rc;
}
@@ -484,11 +518,13 @@
D("%s\n", __func__);
WARN_ON(pctx != f->private_data);
+ mutex_lock(&pcam->vid_lock);
rc = msm_server_try_fmt_mplane(pcam, pfmt);
if (rc)
pr_err("Format %x not found, rc = %d\n",
pfmt->fmt.pix_mp.pixelformat, rc);
+ mutex_unlock(&pcam->vid_lock);
return rc;
}
@@ -795,6 +831,7 @@
mutex_unlock(&pcam->vid_lock);
return rc;
}
+ mutex_init(&pcam_inst->inst_lock);
pcam_inst->sensor_pxlcode = pcam->usr_fmts[0].pxlcode;
pcam_inst->my_index = i;
pcam_inst->pcam = pcam;
@@ -887,7 +924,9 @@
pcam->dev_inst[i] = NULL;
pcam->use_count = 0;
}
+ pcam->dev_inst[i] = NULL;
mutex_unlock(&pcam->vid_lock);
+ mutex_destroy(&pcam_inst->inst_lock);
kfree(pcam_inst);
pr_err("%s: error end", __func__);
return rc;
@@ -986,6 +1025,7 @@
}
mutex_lock(&pcam->vid_lock);
+ mutex_lock(&pcam_inst->inst_lock);
if (pcam_inst->streamon) {
/*something went wrong since instance
@@ -1011,6 +1051,8 @@
v4l2_fh_del(&pcam_inst->eventHandle);
v4l2_fh_exit(&pcam_inst->eventHandle);
}
+ mutex_unlock(&pcam_inst->inst_lock);
+ mutex_destroy(&pcam_inst->inst_lock);
kfree(pcam_inst);
f->private_data = NULL;
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index d0322d1..7d07e7b 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -59,6 +59,7 @@
#define MSM_MERCURY_DRV_NAME "msm_mercury"
#define MSM_I2C_MUX_DRV_NAME "msm_cam_i2c_mux"
#define MSM_IRQ_ROUTER_DRV_NAME "msm_cam_irq_router"
+#define MSM_CPP_DRV_NAME "msm_cpp"
#define MAX_NUM_CSIPHY_DEV 3
#define MAX_NUM_CSID_DEV 4
@@ -68,6 +69,7 @@
#define MAX_NUM_AXI_DEV 2
#define MAX_NUM_VPE_DEV 1
#define MAX_NUM_JPEG_DEV 3
+#define MAX_NUM_CPP_DEV 1
enum msm_cam_subdev_type {
CSIPHY_DEV,
@@ -82,6 +84,7 @@
EEPROM_DEV,
GESTURE_DEV,
IRQ_ROUTER_DEV,
+ CPP_DEV,
};
/* msm queue management APIs*/
@@ -261,6 +264,7 @@
struct v4l2_subdev *vpe_sdev; /* vpe sub device */
struct v4l2_subdev *axi_sdev; /* axi sub device */
struct v4l2_subdev *eeprom_sdev; /* eeprom sub device */
+ struct v4l2_subdev *cpp_sdev;/*cpp sub device*/
struct msm_isp_ops *isp_sdev; /* isp sub device : camif/VFE */
struct msm_cam_config_dev *config_device;
@@ -343,6 +347,7 @@
int is_mem_map_inst;
struct img_plane_info plane_info;
int vbqueue_initialized;
+ struct mutex inst_lock;
};
struct msm_cam_mctl_node {
@@ -540,6 +545,7 @@
struct v4l2_subdev *axi_device[MAX_NUM_AXI_DEV];
struct v4l2_subdev *vpe_device[MAX_NUM_VPE_DEV];
struct v4l2_subdev *gesture_device;
+ struct v4l2_subdev *cpp_device[MAX_NUM_CPP_DEV];
struct v4l2_subdev *irqr_device;
spinlock_t intr_table_lock;
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index cdfad3b..1359792 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -1123,17 +1123,22 @@
struct msm_cam_v4l2_dev_inst, eventHandle);
D("%s\n", __func__);
WARN_ON(pctx != f->private_data);
+
+ mutex_lock(&pcam_inst->inst_lock);
rc = vb2_reqbufs(&pcam_inst->vid_bufq, pb);
if (rc < 0) {
pr_err("%s reqbufs failed %d ", __func__, rc);
+ mutex_unlock(&pcam_inst->inst_lock);
return rc;
}
if (!pb->count) {
/* Deallocation. free buf_offset array */
D("%s Inst %p freeing buffer offsets array",
__func__, pcam_inst);
- for (j = 0 ; j < pcam_inst->buf_count ; j++)
+ for (j = 0 ; j < pcam_inst->buf_count ; j++) {
kfree(pcam_inst->buf_offset[j]);
+ pcam_inst->buf_offset[j] = NULL;
+ }
kfree(pcam_inst->buf_offset);
pcam_inst->buf_offset = NULL;
/* If the userspace has deallocated all the
@@ -1151,6 +1156,7 @@
GFP_KERNEL);
if (!pcam_inst->buf_offset) {
pr_err("%s out of memory ", __func__);
+ mutex_unlock(&pcam_inst->inst_lock);
return -ENOMEM;
}
for (i = 0; i < pb->count; i++) {
@@ -1159,10 +1165,13 @@
pcam_inst->plane_info.num_planes, GFP_KERNEL);
if (!pcam_inst->buf_offset[i]) {
pr_err("%s out of memory ", __func__);
- for (j = i-1 ; j >= 0; j--)
+ for (j = i-1 ; j >= 0; j--) {
kfree(pcam_inst->buf_offset[j]);
+ pcam_inst->buf_offset[j] = NULL;
+ }
kfree(pcam_inst->buf_offset);
pcam_inst->buf_offset = NULL;
+ mutex_unlock(&pcam_inst->inst_lock);
return -ENOMEM;
}
}
@@ -1170,6 +1179,7 @@
pcam_inst->buf_count = pb->count;
D("%s inst %p, buf count %d ", __func__,
pcam_inst, pcam_inst->buf_count);
+ mutex_unlock(&pcam_inst->inst_lock);
return rc;
}
@@ -1177,13 +1187,17 @@
struct v4l2_buffer *pb)
{
/* get the video device */
+ int rc = 0;
struct msm_cam_v4l2_dev_inst *pcam_inst;
pcam_inst = container_of(f->private_data,
struct msm_cam_v4l2_dev_inst, eventHandle);
D("%s\n", __func__);
WARN_ON(pctx != f->private_data);
- return vb2_querybuf(&pcam_inst->vid_bufq, pb);
+ mutex_lock(&pcam_inst->inst_lock);
+ rc = vb2_querybuf(&pcam_inst->vid_bufq, pb);
+ mutex_unlock(&pcam_inst->inst_lock);
+ return rc;
}
static int msm_mctl_v4l2_qbuf(struct file *f, void *pctx,
@@ -1198,8 +1212,10 @@
D("%s Inst = %p\n", __func__, pcam_inst);
WARN_ON(pctx != f->private_data);
+ mutex_lock(&pcam_inst->inst_lock);
if (!pcam_inst->buf_offset) {
pr_err("%s Buffer is already released. Returning. ", __func__);
+ mutex_unlock(&pcam_inst->inst_lock);
return -EINVAL;
}
@@ -1207,6 +1223,7 @@
/* Reject the buffer if planes array was not allocated */
if (pb->m.planes == NULL) {
pr_err("%s Planes array is null ", __func__);
+ mutex_unlock(&pcam_inst->inst_lock);
return -EINVAL;
}
for (i = 0; i < pcam_inst->plane_info.num_planes; i++) {
@@ -1232,6 +1249,7 @@
rc = vb2_qbuf(&pcam_inst->vid_bufq, pb);
D("%s, videobuf_qbuf returns %d\n", __func__, rc);
+ mutex_unlock(&pcam_inst->inst_lock);
return rc;
}
@@ -1246,10 +1264,16 @@
D("%s\n", __func__);
WARN_ON(pctx != f->private_data);
+ mutex_lock(&pcam_inst->inst_lock);
+ if (0 == pcam_inst->streamon) {
+ mutex_unlock(&pcam_inst->inst_lock);
+ return -EACCES;
+ }
rc = vb2_dqbuf(&pcam_inst->vid_bufq, pb, f->f_flags & O_NONBLOCK);
D("%s, videobuf_dqbuf returns %d\n", __func__, rc);
+ mutex_unlock(&pcam_inst->inst_lock);
return rc;
}
@@ -1266,9 +1290,13 @@
D("%s Inst %p\n", __func__, pcam_inst);
WARN_ON(pctx != f->private_data);
+ mutex_lock(&pcam->mctl_node.dev_lock);
+ mutex_lock(&pcam_inst->inst_lock);
if ((buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
(buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
pr_err("%s Invalid buffer type ", __func__);
+ mutex_unlock(&pcam_inst->inst_lock);
+ mutex_unlock(&pcam->mctl_node.dev_lock);
return -EINVAL;
}
@@ -1277,9 +1305,9 @@
rc = vb2_streamon(&pcam_inst->vid_bufq, buf_type);
D("%s, videobuf_streamon returns %d\n", __func__, rc);
- mutex_lock(&pcam->mctl_node.dev_lock);
/* turn HW (VFE/sensor) streaming */
pcam_inst->streamon = 1;
+ mutex_unlock(&pcam_inst->inst_lock);
mutex_unlock(&pcam->mctl_node.dev_lock);
D("%s rc = %d\n", __func__, rc);
return rc;
@@ -1307,14 +1335,16 @@
/* first turn of HW (VFE/sensor) streaming so that buffers are
not in use when we free the buffers */
mutex_lock(&pcam->mctl_node.dev_lock);
+ mutex_lock(&pcam_inst->inst_lock);
pcam_inst->streamon = 0;
- mutex_unlock(&pcam->mctl_node.dev_lock);
if (rc < 0)
pr_err("%s: hw failed to stop streaming\n", __func__);
/* stop buffer streaming */
rc = vb2_streamoff(&pcam_inst->vid_bufq, buf_type);
D("%s, videobuf_streamoff returns %d\n", __func__, rc);
+ mutex_unlock(&pcam_inst->inst_lock);
+ mutex_unlock(&pcam->mctl_node.dev_lock);
return rc;
}
diff --git a/drivers/media/video/msm/sensors/imx074_v4l2.c b/drivers/media/video/msm/sensors/imx074_v4l2.c
index 3d23337..ddf0754 100644
--- a/drivers/media/video/msm/sensors/imx074_v4l2.c
+++ b/drivers/media/video/msm/sensors/imx074_v4l2.c
@@ -276,7 +276,7 @@
.sensor_config = msm_sensor_config,
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
- .sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines,
+ .sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines1,
.sensor_get_csi_params = msm_sensor_get_csi_params,
};
diff --git a/drivers/media/video/msm/sensors/imx091.c b/drivers/media/video/msm/sensors/imx091.c
index 49442e9..7fda037 100644
--- a/drivers/media/video/msm/sensors/imx091.c
+++ b/drivers/media/video/msm/sensors/imx091.c
@@ -303,7 +303,7 @@
.sensor_config = msm_sensor_config,
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
- .sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines,
+ .sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines1,
.sensor_get_csi_params = msm_sensor_get_csi_params,
};
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index 8ab3963..be1efe0 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -16,7 +16,7 @@
#include "msm_camera_i2c_mux.h"
/*=============================================================*/
-int32_t msm_sensor_adjust_frame_lines(struct msm_sensor_ctrl_t *s_ctrl,
+int32_t msm_sensor_adjust_frame_lines1(struct msm_sensor_ctrl_t *s_ctrl,
uint16_t res)
{
uint16_t cur_line = 0;
@@ -50,6 +50,45 @@
return 0;
}
+int32_t msm_sensor_adjust_frame_lines2(struct msm_sensor_ctrl_t *s_ctrl,
+ uint16_t res)
+{
+ uint16_t cur_line = 0;
+ uint16_t exp_fl_lines = 0;
+ uint8_t int_time[3];
+ if (s_ctrl->sensor_exp_gain_info) {
+ if (s_ctrl->prev_gain && s_ctrl->prev_line &&
+ s_ctrl->func_tbl->sensor_write_exp_gain)
+ s_ctrl->func_tbl->sensor_write_exp_gain(
+ s_ctrl,
+ s_ctrl->prev_gain,
+ s_ctrl->prev_line);
+
+ msm_camera_i2c_read_seq(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->coarse_int_time_addr-1,
+ &int_time[0], 3);
+ cur_line |= int_time[0] << 12;
+ cur_line |= int_time[1] << 4;
+ cur_line |= int_time[2] >> 4;
+ exp_fl_lines = cur_line +
+ s_ctrl->sensor_exp_gain_info->vert_offset;
+ if (exp_fl_lines > s_ctrl->msm_sensor_reg->
+ output_settings[res].frame_length_lines)
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_output_reg_addr->
+ frame_length_lines,
+ exp_fl_lines,
+ MSM_CAMERA_I2C_WORD_DATA);
+ CDBG("%s cur_line %x cur_fl_lines %x, exp_fl_lines %x\n",
+ __func__,
+ cur_line,
+ s_ctrl->msm_sensor_reg->
+ output_settings[res].frame_length_lines,
+ exp_fl_lines);
+ }
+ return 0;
+}
+
int32_t msm_sensor_write_init_settings(struct msm_sensor_ctrl_t *s_ctrl)
{
int32_t rc;
diff --git a/drivers/media/video/msm/sensors/msm_sensor.h b/drivers/media/video/msm/sensors/msm_sensor.h
index b1e584d..a3ddaa7 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -236,7 +236,10 @@
int32_t msm_sensor_write_output_settings(struct msm_sensor_ctrl_t *s_ctrl,
uint16_t res);
-int32_t msm_sensor_adjust_frame_lines(struct msm_sensor_ctrl_t *s_ctrl,
+int32_t msm_sensor_adjust_frame_lines1(struct msm_sensor_ctrl_t *s_ctrl,
+ uint16_t res);
+
+int32_t msm_sensor_adjust_frame_lines2(struct msm_sensor_ctrl_t *s_ctrl,
uint16_t res);
int32_t msm_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl,
diff --git a/drivers/media/video/msm/sensors/ov2720.c b/drivers/media/video/msm/sensors/ov2720.c
index 03f1af1..e4c5061 100644
--- a/drivers/media/video/msm/sensors/ov2720.c
+++ b/drivers/media/video/msm/sensors/ov2720.c
@@ -783,7 +783,7 @@
.sensor_config = msm_sensor_config,
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
- .sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines,
+ .sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines2,
.sensor_get_csi_params = msm_sensor_get_csi_params,
};
diff --git a/drivers/media/video/msm/sensors/s5k3l1yx.c b/drivers/media/video/msm/sensors/s5k3l1yx.c
index d7aeb74..c24da00 100644
--- a/drivers/media/video/msm/sensors/s5k3l1yx.c
+++ b/drivers/media/video/msm/sensors/s5k3l1yx.c
@@ -652,7 +652,7 @@
.sensor_config = msm_sensor_config,
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
- .sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines,
+ .sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines1,
.sensor_get_csi_params = msm_sensor_get_csi_params,
};
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index f2bb65f..e21de29 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -637,6 +637,7 @@
__func__, tmp_cmd.type, (uint32_t)tmp_cmd.value,
tmp_cmd.length, tmp_cmd.status, rc);
kfree(ctrl_data);
+ ctrl_data = NULL;
return rc;
}
@@ -1894,8 +1895,17 @@
case GESTURE_DEV:
g_server_dev.gesture_device = sd;
break;
+
case IRQ_ROUTER_DEV:
g_server_dev.irqr_device = sd;
+
+ case CPP_DEV:
+ if (index >= MAX_NUM_CPP_DEV) {
+ pr_err("%s Invalid CPP idx %d", __func__, index);
+ err = -EINVAL;
+ break;
+ }
+ g_server_dev.cpp_device[index] = sd;
break;
default:
break;
@@ -2396,6 +2406,7 @@
/* Next, copy the userspace event ctrl structure */
if (copy_from_user((void *)&u_isp_event, user_ptr,
sizeof(struct msm_isp_event_ctrl))) {
+ rc = -EFAULT;
break;
}
/* Save the pointer of the user allocated command buffer*/
@@ -2407,6 +2418,7 @@
&ev, fp->f_flags & O_NONBLOCK);
if (rc < 0) {
pr_err("no pending events?");
+ rc = -EFAULT;
break;
}
/* Use k_isp_event to point to the event_ctrl structure
@@ -2436,6 +2448,7 @@
break;
}
kfree(k_msg_value);
+ k_msg_value = NULL;
}
}
}
@@ -2448,6 +2461,7 @@
break;
}
kfree(k_isp_event);
+ k_isp_event = NULL;
/* Copy the v4l2_event structure back to the user*/
if (copy_to_user((void __user *)arg, &ev,
diff --git a/drivers/misc/tsif.c b/drivers/misc/tsif.c
index 2b09d7c..aeda38c 100644
--- a/drivers/misc/tsif.c
+++ b/drivers/misc/tsif.c
@@ -304,7 +304,9 @@
for (i = size-1; i >= 0; i--) {
int tmp;
g = table + i;
- tmp = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_DISABLE);
+ tmp = gpio_tlmm_config(GPIO_CFG(GPIO_PIN(g->gpio_cfg),
+ 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+ GPIO_CFG_DISABLE);
if (tmp) {
pr_err("gpio_tlmm_config(0x%08x, GPIO_CFG_DISABLE)"
" <%s> failed: %d\n",
@@ -681,7 +683,7 @@
while (tsif_device->xfer[0].busy ||
tsif_device->xfer[1].busy) {
msm_dmov_flush(tsif_device->dma, 1);
- msleep(10);
+ usleep(10000);
}
}
tsif_device->state = tsif_state_stopped;
@@ -1031,6 +1033,15 @@
return rc;
}
tsif_device->state = tsif_state_running;
+
+ /* make sure the GPIO's are set up */
+ rc = tsif_start_gpios(tsif_device);
+ if (rc) {
+ dev_err(&tsif_device->pdev->dev, "failed to start GPIOs\n");
+ tsif_dma_exit(tsif_device);
+ return rc;
+ }
+
/*
* DMA should be scheduled prior to TSIF hardware initialization,
* otherwise "bus error" will be reported by Data Mover
@@ -1046,6 +1057,7 @@
rc = tsif_start_hw(tsif_device);
if (rc) {
dev_err(&tsif_device->pdev->dev, "Unable to start HW\n");
+ tsif_stop_gpios(tsif_device);
tsif_dma_exit(tsif_device);
tsif_clock(tsif_device, 0);
return rc;
@@ -1067,10 +1079,19 @@
{
dev_info(&tsif_device->pdev->dev, "%s, state %d\n", __func__,
(int)tsif_device->state);
- /*
- * DMA should be flushed/stopped prior to TSIF hardware stop,
- * otherwise "bus error" will be reported by Data Mover
+
+ /* turn off the GPIO's to prevent new data from entering */
+ tsif_stop_gpios(tsif_device);
+
+ /* we unfortunately must sleep here to give the ADM time to
+ * complete any outstanding reads after the GPIO's are turned
+ * off. There is no indication from the ADM hardware that
+ * there are any outstanding reads on the bus, and if we
+ * stop the TSIF too quickly, it can cause a bus error.
*/
+ msleep(100);
+
+ /* now we can stop the core */
tsif_stop_hw(tsif_device);
tsif_dma_exit(tsif_device);
tsif_clock(tsif_device, 0);
@@ -1317,9 +1338,6 @@
}
dev_info(&pdev->dev, "remapped phys 0x%08x => virt %p\n",
tsif_device->memres->start, tsif_device->base);
- rc = tsif_start_gpios(tsif_device);
- if (rc)
- goto err_gpio;
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
@@ -1355,8 +1373,6 @@
free_irq(tsif_device->irq, tsif_device);
err_irq:
tsif_debugfs_exit(tsif_device);
- tsif_stop_gpios(tsif_device);
-err_gpio:
iounmap(tsif_device->base);
err_ioremap:
err_rgn:
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index 81c6b65..4d7553e 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1687,7 +1687,7 @@
/* map clocks */
if (data->tsif_pclk) {
- device->tsif_pclk = clk_get(NULL, data->tsif_pclk);
+ device->tsif_pclk = clk_get(&pdev->dev, data->tsif_pclk);
if (IS_ERR(device->tsif_pclk)) {
pr_err("tspp: failed to get %s",
data->tsif_pclk);
@@ -1697,7 +1697,7 @@
}
}
if (data->tsif_ref_clk) {
- device->tsif_ref_clk = clk_get(NULL, data->tsif_ref_clk);
+ device->tsif_ref_clk = clk_get(&pdev->dev, data->tsif_ref_clk);
if (IS_ERR(device->tsif_ref_clk)) {
pr_err("tspp: failed to get %s",
data->tsif_ref_clk);
diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c
index a153de1..2972af0 100644
--- a/drivers/net/usb/rmnet_usb_ctrl.c
+++ b/drivers/net/usb/rmnet_usb_ctrl.c
@@ -521,8 +521,6 @@
dev->is_opened = 0;
mutex_unlock(&dev->dev_lock);
- rmnet_usb_ctrl_stop_rx(dev);
-
if (is_dev_connected(dev))
usb_kill_anchored_urbs(&dev->tx_submitted);
diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c
index 9e1e252..55020a1 100644
--- a/drivers/net/usb/rmnet_usb_data.c
+++ b/drivers/net/usb/rmnet_usb_data.c
@@ -604,6 +604,7 @@
static const struct driver_info rmnet_info_pid9034 = {
.description = "RmNET net device",
+ .flags = FLAG_SEND_ZLP,
.bind = rmnet_usb_bind,
.tx_fixup = rmnet_usb_tx_fixup,
.rx_fixup = rmnet_usb_rx_fixup,
@@ -613,6 +614,7 @@
static const struct driver_info rmnet_info_pid9048 = {
.description = "RmNET net device",
+ .flags = FLAG_SEND_ZLP,
.bind = rmnet_usb_bind,
.tx_fixup = rmnet_usb_tx_fixup,
.rx_fixup = rmnet_usb_rx_fixup,
@@ -622,6 +624,7 @@
static const struct driver_info rmnet_info_pid904c = {
.description = "RmNET net device",
+ .flags = FLAG_SEND_ZLP,
.bind = rmnet_usb_bind,
.tx_fixup = rmnet_usb_tx_fixup,
.rx_fixup = rmnet_usb_rx_fixup,
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index 24da4d1..36414e0 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -1979,7 +1979,7 @@
}
}
/* Leave some slots for messaging space */
- if (opensl1[1] == 0 && opensl1[0] == 0)
+ if (opensl1[1] <= 0 && opensl1[0] <= 0)
return -EXFULL;
if (opensl1[1] > opensl1[0]) {
int temp = opensl1[0];
@@ -2184,7 +2184,7 @@
}
}
/* Leave some slots for messaging space */
- if (opensl3[1] == 0 && opensl3[0] == 0)
+ if (opensl3[1] <= 0 && opensl3[0] <= 0)
return -EXFULL;
/* swap 1st and 2nd bucket if 2nd bucket has more open slots */
if (opensl3[1] > opensl3[0]) {
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 2c86e83..f2c881d 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -405,9 +405,17 @@
bytes_sent = 0;
}
- /* We'll send in chunks of SPI_MAX_LEN if larger */
- bytes_to_send = dd->tx_bytes_remaining / SPI_MAX_LEN ?
- SPI_MAX_LEN : dd->tx_bytes_remaining;
+ /* We'll send in chunks of SPI_MAX_LEN if larger than
+ * 4K bytes for targets that doesn't support infinite
+ * mode. Make sure this doesn't happen on targets that
+ * support infinite mode.
+ */
+ if (!dd->pdata->infinite_mode)
+ bytes_to_send = dd->tx_bytes_remaining / SPI_MAX_LEN ?
+ SPI_MAX_LEN : dd->tx_bytes_remaining;
+ else
+ bytes_to_send = dd->tx_bytes_remaining;
+
num_transfers = DIV_ROUND_UP(bytes_to_send, dd->bytes_per_word);
dd->unaligned_len = bytes_to_send % dd->burst_size;
num_rows = bytes_to_send / dd->burst_size;
@@ -512,12 +520,11 @@
msm_dmov_enqueue_cmd(dd->rx_dma_chan, &dd->rx_hdr);
}
-/* SPI core can send maximum of 4K transfers, because there is HW problem
- with infinite mode.
- Therefore, we are sending several chunks of 3K or less (depending on how
- much is left).
- Upon completion we send the next chunk, or complete the transfer if
- everything is finished.
+/* SPI core on targets that does not support infinite mode can send maximum of
+ 4K transfers, Therefore, we are sending several chunks of 3K or less
+ (depending on how much is left). Upon completion we send the next chunk,
+ or complete the transfer if everything is finished. On targets that support
+ infinite mode, we send all the bytes in as single chunk.
*/
static int msm_spi_dm_send_next(struct msm_spi *dd)
{
@@ -527,8 +534,10 @@
if (dd->mode != SPI_DMOV_MODE)
return 0;
- /* We need to send more chunks, if we sent max last time */
- if (dd->tx_bytes_remaining > SPI_MAX_LEN) {
+ /* On targets which does not support infinite mode,
+ We need to send more chunks, if we sent max last time */
+ if ((!dd->pdata->infinite_mode) &&
+ (dd->tx_bytes_remaining > SPI_MAX_LEN)) {
dd->tx_bytes_remaining -= SPI_MAX_LEN;
if (msm_spi_set_state(dd, SPI_OP_STATE_RESET))
return 0;
@@ -1766,6 +1775,8 @@
of_property_read_u32(node, "spi-max-frequency",
&pdata->max_clock_speed);
+ of_property_read_u32(node, "infinite_mode",
+ &pdata->infinite_mode);
return pdata;
}
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 3098fbe..fff9465 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -380,6 +380,9 @@
ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next);
+ /*CMD_RUN will be set after, PORT_RESUME gets cleared*/
+ if (ehci->resume_sof_bug)
+ ehci->command &= ~CMD_RUN;
/* restore CMD_RUN, framelist size, and irq threshold */
ehci_writel(ehci, ehci->command, &ehci->regs->command);
ehci->rh_state = EHCI_RH_RUNNING;
@@ -422,6 +425,17 @@
ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
}
+ if (ehci->resume_sof_bug && resume_needed) {
+ /* root hub has only one port.
+ * PORT_RESUME gets cleared automatically. */
+ handshake(ehci, &ehci->regs->port_status[0], PORT_RESUME, 0,
+ 20000);
+ ehci_writel(ehci, ehci_readl(ehci,
+ &ehci->regs->command) | CMD_RUN,
+ &ehci->regs->command);
+ goto skip_clear_resume;
+ }
+
/* msleep for 20ms only if code is trying to resume port */
if (resume_needed) {
spin_unlock_irq(&ehci->lock);
@@ -438,6 +452,8 @@
ehci_vdbg (ehci, "resumed port %d\n", i + 1);
}
}
+
+skip_clear_resume:
(void) ehci_readl(ehci, &ehci->regs->command);
/* maybe re-activate the schedule(s) */
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index a95198c..874c728 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -730,13 +730,6 @@
skip_phy_resume:
- if (!(readl_relaxed(USB_USBCMD) & CMD_RUN) &&
- (readl_relaxed(USB_PORTSC) & PORT_SUSPEND)) {
- writel_relaxed(readl_relaxed(USB_USBCMD) | CMD_RUN ,
- USB_USBCMD);
- dbg_log_event(NULL, "Set RS", readl_relaxed(USB_USBCMD));
- }
-
usb_hcd_resume_root_hub(hcd);
atomic_set(&mehci->in_lpm, 0);
@@ -1246,6 +1239,8 @@
mehci->ehci.susp_sof_bug = 1;
mehci->ehci.reset_sof_bug = 1;
+ mehci->ehci.resume_sof_bug = 1;
+
mehci->ehci.max_log2_irq_thresh = 6;
res = platform_get_resource_byname(pdev,
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 5754170..a0f995c 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -152,6 +152,7 @@
unsigned has_synopsys_hc_bug:1; /* Synopsys HC */
unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */
unsigned susp_sof_bug:1; /*Chip Idea HC*/
+ unsigned resume_sof_bug:1;/*Chip Idea HC*/
unsigned reset_sof_bug:1; /*Chip Idea HC*/
/* required for usb32 quirk */
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index 8b762a2..6d5544a 100644
--- a/drivers/usb/misc/diag_bridge.c
+++ b/drivers/usb/misc/diag_bridge.c
@@ -255,6 +255,7 @@
pipe = usb_sndbulkpipe(dev->udev, dev->out_epAddr);
usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
diag_bridge_write_cb, dev);
+ urb->transfer_flags |= URB_ZERO_PACKET;
usb_anchor_urb(urb, &dev->submitted);
dev->pending_writes++;
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
index db2f40a..1c9de07 100644
--- a/drivers/usb/misc/mdm_data_bridge.c
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -497,6 +497,8 @@
usb_fill_bulk_urb(txurb, dev->udev, dev->bulk_out,
skb->data, skb->len, data_bridge_write_cb, skb);
+ txurb->transfer_flags |= URB_ZERO_PACKET;
+
if (test_bit(SUSPENDED, &dev->flags)) {
usb_anchor_urb(txurb, &dev->delayed);
goto free_urb;
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 79bbce4..2bc7f5b 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -51,7 +51,7 @@
int mdp_rev;
static struct platform_device *mdp_init_pdev;
-static struct regulator *footswitch;
+static struct regulator *footswitch, *hdmi_pll_fs;
static unsigned int mdp_footswitch_on;
struct completion mdp_ppp_comp;
@@ -2122,10 +2122,16 @@
}
disable_irq(mdp_irq);
+ hdmi_pll_fs = regulator_get(&pdev->dev, "hdmi_pll_fs");
+ if (IS_ERR(hdmi_pll_fs))
+ hdmi_pll_fs = NULL;
+
footswitch = regulator_get(&pdev->dev, "vdd");
if (IS_ERR(footswitch))
footswitch = NULL;
else {
+ if (hdmi_pll_fs)
+ regulator_enable(hdmi_pll_fs);
regulator_enable(footswitch);
mdp_footswitch_on = 1;
@@ -2134,6 +2140,8 @@
msleep(20);
regulator_enable(footswitch);
}
+ if (hdmi_pll_fs)
+ regulator_disable(hdmi_pll_fs);
}
mdp_clk = clk_get(&pdev->dev, "core_clk");
@@ -2625,6 +2633,9 @@
return;
}
+ if (hdmi_pll_fs)
+ regulator_enable(hdmi_pll_fs);
+
if (on && !mdp_footswitch_on) {
pr_debug("Enable MDP FS\n");
regulator_enable(footswitch);
@@ -2635,6 +2646,9 @@
mdp_footswitch_on = 0;
}
+ if (hdmi_pll_fs)
+ regulator_disable(hdmi_pll_fs);
+
mutex_unlock(&mdp_suspend_mutex);
}
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index 9174bc5..03b22f1 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -520,7 +520,7 @@
}
wait_for_completion_timeout(&dtv_pipe->comp,
- msecs_to_jiffies(VSYNC_PERIOD*2));
+ msecs_to_jiffies(VSYNC_PERIOD * 3));
mdp_disable_irq(MDP_OVERLAY1_TERM);
if (dtv_pipe->blt_addr)
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index f1a2ada..8dccf78 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -21,7 +21,7 @@
#include <linux/delay.h>
#include <mach/hardware.h>
#include <linux/io.h>
-
+#include <mach/iommu_domains.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
@@ -407,11 +407,10 @@
pr_err("%s: out of memory\n", __func__);
goto register_alloc_fail;
}
-
+ temp->ihdl = NULL;
if (data->iova)
temp->addr = (void *)(data->iova + data->offset);
-#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
- else {
+ else if (mfd->iclient) {
struct ion_handle *srcp_ihdl;
ulong len;
srcp_ihdl = ion_import_fd(mfd->iclient,
@@ -420,22 +419,30 @@
pr_err("%s: ion import fd failed\n", __func__);
goto register_ion_fail;
}
- if (ion_phys(mfd->iclient,
- srcp_ihdl,
- (ulong *)&temp->addr,
- (size_t *)&len)) {
- pr_err("%s: unable to get ion phys\n",
+
+ if (ion_map_iommu(mfd->iclient,
+ srcp_ihdl,
+ DISPLAY_DOMAIN,
+ GEN_POOL,
+ SZ_4K,
+ 0,
+ (ulong *)&temp->addr,
+ (ulong *)&len,
+ 0,
+ ION_IOMMU_UNMAP_DELAYED)) {
+ ion_free(mfd->iclient, srcp_ihdl);
+ pr_err("%s: unable to get ion mapping addr\n",
__func__);
goto register_ion_fail;
}
temp->addr += data->offset;
+ temp->ihdl = srcp_ihdl;
}
-#else
else {
pr_err("%s: only support ion memory\n", __func__);
goto register_ion_fail;
}
-#endif
+
memcpy(&temp->buf_info, data, sizeof(struct msmfb_data));
if (mdp4_overlay_writeback_register_buffer(mfd, temp)) {
pr_err("%s: error registering node\n", __func__);
@@ -514,6 +521,15 @@
list_del(&node->active_entry);
node->state = WITH_CLIENT;
memcpy(data, &node->buf_info, sizeof(struct msmfb_data));
+ if (!data->iova)
+ if (mfd->iclient && node->ihdl) {
+ ion_unmap_iommu(mfd->iclient,
+ node->ihdl,
+ DISPLAY_DOMAIN,
+ GEN_POOL);
+ ion_free(mfd->iclient,
+ node->ihdl);
+ }
} else {
pr_err("node is NULL. Somebody else dequeued?\n");
rc = -ENOBUFS;
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 41e0c18..46e49da 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -554,10 +554,10 @@
}
disable_irq(mdss_res->irq);
- mdss_res->fs = regulator_get(NULL, "gdsc_mdss");
+ mdss_res->fs = regulator_get(&pdev->dev, "vdd");
if (IS_ERR_OR_NULL(mdss_res->fs)) {
mdss_res->fs = NULL;
- pr_err("unable to get gdsc_mdss regulator\n");
+ pr_err("unable to get gdsc regulator\n");
goto error;
}
regulator_enable(mdss_res->fs);
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index c9eb7dd..0658365 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -60,6 +60,7 @@
struct list_head registered_entry;
struct list_head active_entry;
void *addr;
+ struct ion_handle *ihdl;
struct file *pmem_file;
struct msmfb_data buf_info;
struct msmfb_img img;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
index 6fd5656..d7ebd54 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -168,6 +168,28 @@
} else if (operation == DDL_DPB_OP_MARK_FREE) {
dpb_mask->client_mask |= (0x1 << loopc);
*found_frame = *in_out_frame;
+ if ((decoder->meta_data_enable_flag) &&
+ (in_out_frame->vcd_frm.buff_ion_handle)) {
+ struct ddl_context *ddl_context =
+ ddl_get_context();
+ unsigned long *vaddr =
+ (unsigned long *)((u32)
+ in_out_frame->vcd_frm.virtual +
+ decoder->meta_data_offset);
+ DDL_MSG_LOW("%s: Cache clean: vaddr"\
+ " (%p), offset %u, size %u",
+ __func__,
+ in_out_frame->vcd_frm.virtual,
+ decoder->meta_data_offset,
+ decoder->suffix);
+ msm_ion_do_cache_op(
+ ddl_context->video_ion_client,
+ in_out_frame->vcd_frm.\
+ buff_ion_handle,
+ vaddr,
+ (unsigned long)decoder->suffix,
+ ION_IOC_CLEAN_CACHES);
+ }
}
} else {
in_out_frame->vcd_frm.physical = NULL;
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index 3076aa1..ed8b452 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -348,10 +348,15 @@
pmem_fd, kernel_vaddr, buffer_index,
&buff_handle);
if (ion_flag == CACHED && buff_handle) {
+ DBG("%s: Cache invalidate: vaddr (%p), "\
+ "size %u\n", __func__,
+ (void *)kernel_vaddr,
+ vcd_frame_data->alloc_len);
msm_ion_do_cache_op(client_ctx->user_ion_client,
buff_handle,
(unsigned long *) kernel_vaddr,
- (unsigned long)vcd_frame_data->data_len,
+ (unsigned long)vcd_frame_data->\
+ alloc_len,
ION_IOC_INV_CACHES);
}
}
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 3308243..da450fc 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -1659,4 +1659,86 @@
#define MSM_IRQROUTER_CFG_COMPIRQ \
_IOWR('V', BASE_VIDIOC_PRIVATE, void __user *)
+#define MAX_NUM_CPP_STRIPS 8
+
+enum msm_cpp_frame_type {
+ MSM_CPP_OFFLINE_FRAME,
+ MSM_CPP_REALTIME_FRAME,
+};
+
+struct msm_cpp_frame_strip_info {
+ int scale_v_en;
+ int scale_h_en;
+
+ int upscale_v_en;
+ int upscale_h_en;
+
+ int src_start_x;
+ int src_end_x;
+ int src_start_y;
+ int src_end_y;
+
+ /* Padding is required for upscaler because it does not
+ * pad internally like other blocks, also needed for rotation
+ * rotation expects all the blocks in the stripe to be the same size
+ * Padding is done such that all the extra padded pixels
+ * are on the right and bottom
+ */
+ int pad_bottom;
+ int pad_top;
+ int pad_right;
+ int pad_left;
+
+ int v_init_phase;
+ int h_init_phase;
+ int h_phase_step;
+ int v_phase_step;
+
+ int prescale_crop_width_first_pixel;
+ int prescale_crop_width_last_pixel;
+ int prescale_crop_height_first_line;
+ int prescale_crop_height_last_line;
+
+ int postscale_crop_height_first_line;
+ int postscale_crop_height_last_line;
+ int postscale_crop_width_first_pixel;
+ int postscale_crop_width_last_pixel;
+
+ int dst_start_x;
+ int dst_end_x;
+ int dst_start_y;
+ int dst_end_y;
+
+ int bytes_per_pixel;
+ unsigned int source_address;
+ unsigned int destination_address;
+ unsigned int src_stride;
+ unsigned int dst_stride;
+ int rotate_270;
+ int horizontal_flip;
+ int vertical_flip;
+ int scale_output_width;
+ int scale_output_height;
+};
+
+struct msm_cpp_frame_info_t {
+ int32_t frame_id;
+ uint32_t inst_id;
+ uint32_t client_id;
+ enum msm_cpp_frame_type frame_type;
+ uint32_t num_strips;
+ struct msm_cpp_frame_strip_info *strip_info;
+};
+
+#define VIDIOC_MSM_CPP_CFG \
+ _IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_CPP_GET_EVENTPAYLOAD \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_CPP_GET_INST_INFO \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 2, struct msm_camera_v4l2_ioctl_t)
+
+#define V4L2_EVENT_CPP_FRAME_DONE (V4L2_EVENT_PRIVATE_START + 0)
+
#endif /* __LINUX_MSM_CAMERA_H */
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 431dedf..c770f13 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -1127,6 +1127,7 @@
#define AC3_DECODER 0x00010BF6
#define EAC3_DECODER 0x00010C3C
#define DTS 0x00010D88
+#define DTS_LBR 0x00010DBB
#define ATRAC 0x00010D89
#define MAT 0x00010D8A
#define G711_ALAW_FS 0x00010BF7
@@ -1145,6 +1146,13 @@
#define ASM_ENCDEC_IMMDIATE_DECODE 0x00010C14
#define ASM_ENCDEC_CFG_BLK 0x00010C2C
+#define ASM_STREAM_CMD_OPEN_READ_COMPRESSED 0x00010D95
+struct asm_stream_cmd_open_read_compressed {
+ struct apr_hdr hdr;
+ u32 uMode;
+ u32 frame_per_buf;
+} __packed;
+
#define ASM_STREAM_CMD_OPEN_WRITE 0x00010BCA
struct asm_stream_cmd_open_write {
struct apr_hdr hdr;
@@ -1185,6 +1193,17 @@
u16 afe_port_id;
} __packed;
+#define ADM_CMD_CONNECT_AFE_PORT_V2 0x00010332
+
+struct adm_cmd_connect_afe_port_v2 {
+ struct apr_hdr hdr;
+ u8 mode; /*mode represent the interface is for RX or TX*/
+ u8 session_id; /*ASM session ID*/
+ u16 afe_port_id;
+ u32 num_channels;
+ u32 sampleing_rate;
+} __packed;
+
#define ASM_STREAM_CMD_SET_ENCDEC_PARAM 0x00010C10
#define ASM_STREAM_CMD_GET_ENCDEC_PARAM 0x00010C11
#define ASM_ENCDEC_CFG_BLK_ID 0x00010C2C
diff --git a/include/sound/compress_offload.h b/include/sound/compress_offload.h
index 9769dea..e59d29c 100644
--- a/include/sound/compress_offload.h
+++ b/include/sound/compress_offload.h
@@ -123,6 +123,16 @@
};
/**
+ * struct snd_compr_audio_info: compressed input audio information
+ * @frame_size: legth of the encoded frame with valid data
+ * @reserved: reserved for furture use
+ */
+struct snd_compr_audio_info {
+ uint32_t frame_size;
+ uint32_t reserved[15];
+};
+
+/**
* compress path ioctl definitions
* SNDRV_COMPRESS_GET_CAPS: Query capability of DSP
* SNDRV_COMPRESS_GET_CODEC_CAPS: Query capability of a codec
diff --git a/include/sound/compress_params.h b/include/sound/compress_params.h
index 9c7a1ea..75558bf 100644
--- a/include/sound/compress_params.h
+++ b/include/sound/compress_params.h
@@ -70,10 +70,14 @@
#define SND_AUDIOCODEC_IEC61937 ((__u32) 0x0000000B)
#define SND_AUDIOCODEC_G723_1 ((__u32) 0x0000000C)
#define SND_AUDIOCODEC_G729 ((__u32) 0x0000000D)
-#define SND_AUDIOCODEC_AC3 ((__u32) 0x0000000E)
-#define SND_AUDIOCODEC_DTS ((__u32) 0x0000000F)
-#define SND_AUDIOCODEC_AC3_PASS_THROUGH ((__u32) 0x00000010)
-#define SND_AUDIOCODEC_WMA_PRO ((__u32) 0x00000011)
+#define SND_AUDIOCODEC_AC3 ((__u32) 0x0000000E)
+#define SND_AUDIOCODEC_DTS ((__u32) 0x0000000F)
+#define SND_AUDIOCODEC_AC3_PASS_THROUGH ((__u32) 0x00000010)
+#define SND_AUDIOCODEC_WMA_PRO ((__u32) 0x00000011)
+#define SND_AUDIOCODEC_DTS_PASS_THROUGH ((__u32) 0x00000012)
+#define SND_AUDIOCODEC_DTS_LBR ((__u32) 0x00000013)
+#define SND_AUDIOCODEC_DTS_TRANSCODE_LOOPBACK ((__u32) 0x00000014)
+
/*
* Profile and modes are listed with bit masks. This allows for a
* more compact representation of fields that will not evolve
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index 1e647a2..84e3150 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -48,6 +48,7 @@
#define FORMAT_ATRAC 0x0016
#define FORMAT_MAT 0x0017
#define FORMAT_AAC 0x0018
+#define FORMAT_DTS_LBR 0x0019
#define ENCDEC_SBCBITRATE 0x0001
#define ENCDEC_IMMEDIATE_DECODE 0x0002
@@ -180,6 +181,8 @@
int q6asm_open_read(struct audio_client *ac, uint32_t format);
+int q6asm_open_read_compressed(struct audio_client *ac, uint32_t format);
+
int q6asm_open_write(struct audio_client *ac, uint32_t format);
int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format);
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index e85e9f5..a34b294 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -114,6 +114,11 @@
static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
static struct snd_soc_dai_driver tabla_dai[];
static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
+static int tabla_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
+static int tabla_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
+
enum tabla_bandgap_type {
TABLA_BANDGAP_OFF = 0,
@@ -3931,50 +3936,277 @@
return 0;
}
+
+static struct snd_soc_dapm_widget tabla_dapm_aif_in_widgets[] = {
+
+ SND_SOC_DAPM_AIF_IN_E("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 1,
+ 0, tabla_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_IN_E("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 2,
+ 0, tabla_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_IN_E("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 3,
+ 0, tabla_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_IN_E("SLIM RX4", "AIF3 Playback", 0, SND_SOC_NOPM, 4,
+ 0, tabla_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_IN_E("SLIM RX5", "AIF3 Playback", 0, SND_SOC_NOPM, 5,
+ 0, tabla_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_IN_E("SLIM RX6", "AIF2 Playback", 0, SND_SOC_NOPM, 6,
+ 0, tabla_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_IN_E("SLIM RX7", "AIF2 Playback", 0, SND_SOC_NOPM, 7,
+ 0, tabla_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static struct snd_soc_dapm_widget tabla_dapm_aif_out_widgets[] = {
+
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX1", "AIF2 Capture", 0, SND_SOC_NOPM, 1,
+ 0, tabla_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX2", "AIF2 Capture", 0, SND_SOC_NOPM, 2,
+ 0, tabla_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX3", "AIF3 Capture", 0, SND_SOC_NOPM, 3,
+ 0, tabla_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX4", "AIF2 Capture", 0, SND_SOC_NOPM, 4,
+ 0, tabla_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX5", "AIF3 Capture", 0, SND_SOC_NOPM, 5,
+ 0, tabla_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX6", "AIF2 Capture", 0, SND_SOC_NOPM, 6,
+ 0, tabla_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX7", "AIF1 Capture", 0, SND_SOC_NOPM, 7,
+ 0, tabla_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX8", "AIF1 Capture", 0, SND_SOC_NOPM, 8,
+ 0, tabla_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX9", "AIF1 Capture", 0, SND_SOC_NOPM, 9,
+ 0, tabla_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX10", "AIF1 Capture", 0, SND_SOC_NOPM, 10,
+ 0, tabla_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static int tabla_set_interpolator_rate(struct snd_soc_dai *dai,
+ u8 rx_fs_rate_reg_val, u32 compander_fs, u32 sample_rate)
+{
+ u32 i, j;
+ u8 rx_mix1_inp;
+ u16 rx_mix_1_reg_1, rx_mix_1_reg_2;
+ u16 rx_fs_reg;
+ u8 rx_mix_1_reg_1_val, rx_mix_1_reg_2_val;
+ struct snd_soc_codec *codec = dai->codec;
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_widget *w = tabla_dapm_aif_in_widgets;
+
+ for (i = 0; i < ARRAY_SIZE(tabla_dapm_aif_in_widgets); i++) {
+
+ if (strncmp(dai->driver->playback.stream_name, w[i].sname, 13))
+ continue;
+
+ rx_mix1_inp = w[i].shift + 4;
+
+ if ((rx_mix1_inp < 0x5) || (rx_mix1_inp > 0xB)) {
+
+ pr_err("%s: Invalid SLIM RX%u port. widget = %s\n",
+ __func__, rx_mix1_inp - 4 , w[i].name);
+ return -EINVAL;
+ }
+
+ rx_mix_1_reg_1 = TABLA_A_CDC_CONN_RX1_B1_CTL;
+
+ for (j = 0; j < NUM_INTERPOLATORS; j++) {
+
+ rx_mix_1_reg_2 = rx_mix_1_reg_1 + 1;
+
+ rx_mix_1_reg_1_val = snd_soc_read(codec,
+ rx_mix_1_reg_1);
+ rx_mix_1_reg_2_val = snd_soc_read(codec,
+ rx_mix_1_reg_2);
+
+ if (((rx_mix_1_reg_1_val & 0x0F) == rx_mix1_inp) ||
+ (((rx_mix_1_reg_1_val >> 4) & 0x0F) == rx_mix1_inp)
+ || ((rx_mix_1_reg_2_val & 0x0F) == rx_mix1_inp)) {
+
+ rx_fs_reg = TABLA_A_CDC_RX1_B5_CTL + 8 * j;
+
+ pr_debug("%s: %s connected to RX%u\n", __func__,
+ w[i].name, j + 1);
+
+ pr_debug("%s: set RX%u sample rate to %u\n",
+ __func__, j + 1, sample_rate);
+
+ snd_soc_update_bits(codec, rx_fs_reg,
+ 0xE0, rx_fs_rate_reg_val);
+
+ if (comp_rx_path[j] < COMPANDER_MAX)
+ tabla->comp_fs[comp_rx_path[j]]
+ = compander_fs;
+ }
+ if (j <= 2)
+ rx_mix_1_reg_1 += 3;
+ else
+ rx_mix_1_reg_1 += 2;
+ }
+ }
+ return 0;
+}
+
+static int tabla_set_decimator_rate(struct snd_soc_dai *dai,
+ u8 tx_fs_rate_reg_val, u32 sample_rate)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct snd_soc_dapm_widget *w = tabla_dapm_aif_out_widgets;
+
+ u32 i, tx_port;
+ u16 tx_port_reg, tx_fs_reg;
+ u8 tx_port_reg_val;
+ s8 decimator;
+
+ for (i = 0; i < ARRAY_SIZE(tabla_dapm_aif_out_widgets); i++) {
+
+ if (strncmp(dai->driver->capture.stream_name, w[i].sname, 12))
+ continue;
+
+ tx_port = w[i].shift;
+
+ if ((tx_port < 1) || (tx_port > NUM_DECIMATORS)) {
+ pr_err("%s: Invalid SLIM TX%u port. widget = %s\n",
+ __func__, tx_port, w[i].name);
+ return -EINVAL;
+ }
+
+ tx_port_reg = TABLA_A_CDC_CONN_TX_SB_B1_CTL + (tx_port - 1);
+ tx_port_reg_val = snd_soc_read(codec, tx_port_reg);
+
+ decimator = 0;
+
+ if ((tx_port >= 1) && (tx_port <= 6)) {
+
+ tx_port_reg_val = tx_port_reg_val & 0x0F;
+ if (tx_port_reg_val == 0x8)
+ decimator = tx_port;
+
+ } else if ((tx_port >= 7) && (tx_port <= NUM_DECIMATORS)) {
+
+ tx_port_reg_val = tx_port_reg_val & 0x1F;
+
+ if ((tx_port_reg_val >= 0x8) &&
+ (tx_port_reg_val <= 0x11)) {
+
+ decimator = (tx_port_reg_val - 0x8) + 1;
+ }
+ }
+
+ if (decimator) { /* SLIM_TX port has a DEC as input */
+
+ tx_fs_reg = TABLA_A_CDC_TX1_CLK_FS_CTL +
+ 8 * (decimator - 1);
+
+ pr_debug("%s: set DEC%u (-> SLIM_TX%u) rate to %u\n",
+ __func__, decimator, tx_port, sample_rate);
+
+ snd_soc_update_bits(codec, tx_fs_reg, 0x07,
+ tx_fs_rate_reg_val);
+
+ } else {
+ if ((tx_port_reg_val >= 0x1) &&
+ (tx_port_reg_val <= 0x7)) {
+
+ pr_debug("%s: RMIX%u going to SLIM TX%u\n",
+ __func__, tx_port_reg_val, tx_port);
+
+ } else if ((tx_port_reg_val >= 0x8) &&
+ (tx_port_reg_val <= 0x11)) {
+
+ pr_err("%s: ERROR: Should not be here\n",
+ __func__);
+ pr_err("%s: ERROR: DEC connected to SLIM TX%u\n"
+ , __func__, tx_port);
+ return -EINVAL;
+
+ } else if (tx_port_reg_val == 0) {
+ pr_debug("%s: no signal to SLIM TX%u\n",
+ __func__, tx_port);
+ } else {
+ pr_err("%s: ERROR: wrong signal to SLIM TX%u\n"
+ , __func__, tx_port);
+ pr_err("%s: ERROR: wrong signal = %u\n"
+ , __func__, tx_port_reg_val);
+ return -EINVAL;
+ }
+ }
+ }
+ return 0;
+}
+
static int tabla_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
- u8 path, shift;
- u16 tx_fs_reg, rx_fs_reg;
- u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
+ u8 tx_fs_rate_reg_val, rx_fs_rate_reg_val;
u32 compander_fs;
+ int ret;
pr_debug("%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__,
- dai->name, dai->id, params_rate(params),
- params_channels(params));
+ dai->name, dai->id, params_rate(params),
+ params_channels(params));
switch (params_rate(params)) {
case 8000:
- tx_fs_rate = 0x00;
- rx_fs_rate = 0x00;
+ tx_fs_rate_reg_val = 0x00;
+ rx_fs_rate_reg_val = 0x00;
compander_fs = COMPANDER_FS_8KHZ;
break;
case 16000:
- tx_fs_rate = 0x01;
- rx_fs_rate = 0x20;
+ tx_fs_rate_reg_val = 0x01;
+ rx_fs_rate_reg_val = 0x20;
compander_fs = COMPANDER_FS_16KHZ;
break;
case 32000:
- tx_fs_rate = 0x02;
- rx_fs_rate = 0x40;
+ tx_fs_rate_reg_val = 0x02;
+ rx_fs_rate_reg_val = 0x40;
compander_fs = COMPANDER_FS_32KHZ;
break;
case 48000:
- tx_fs_rate = 0x03;
- rx_fs_rate = 0x60;
+ tx_fs_rate_reg_val = 0x03;
+ rx_fs_rate_reg_val = 0x60;
compander_fs = COMPANDER_FS_48KHZ;
break;
case 96000:
- tx_fs_rate = 0x04;
- rx_fs_rate = 0x80;
+ tx_fs_rate_reg_val = 0x04;
+ rx_fs_rate_reg_val = 0x80;
compander_fs = COMPANDER_FS_96KHZ;
break;
case 192000:
- tx_fs_rate = 0x05;
- rx_fs_rate = 0xA0;
+ tx_fs_rate_reg_val = 0x05;
+ rx_fs_rate_reg_val = 0xA0;
compander_fs = COMPANDER_FS_192KHZ;
break;
default:
@@ -3983,105 +4215,76 @@
return -EINVAL;
}
+ switch (substream->stream) {
+ case SNDRV_PCM_STREAM_CAPTURE:
- /**
- * If current dai is a tx dai, set sample rate to
- * all the txfe paths that are currently not active
- */
- if ((dai->id == AIF1_CAP) || (dai->id == AIF2_CAP) ||
- (dai->id == AIF3_CAP)) {
-
- tx_state = snd_soc_read(codec,
- TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL);
-
- for (path = 1, shift = 0;
- path <= NUM_DECIMATORS; path++, shift++) {
-
- if (path == BITS_PER_REG + 1) {
- shift = 0;
- tx_state = snd_soc_read(codec,
- TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL);
- }
-
- if (!(tx_state & (1 << shift))) {
- tx_fs_reg = TABLA_A_CDC_TX1_CLK_FS_CTL
- + (BITS_PER_REG*(path-1));
- snd_soc_update_bits(codec, tx_fs_reg,
- 0x07, tx_fs_rate);
- }
+ ret = tabla_set_decimator_rate(dai, tx_fs_rate_reg_val,
+ params_rate(params));
+ if (ret < 0) {
+ pr_err("%s: set decimator rate failed %d\n", __func__,
+ ret);
+ return ret;
}
+
if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
snd_soc_update_bits(codec,
- TABLA_A_CDC_CLK_TX_I2S_CTL,
- 0x20, 0x20);
+ TABLA_A_CDC_CLK_TX_I2S_CTL, 0x20, 0x20);
break;
case SNDRV_PCM_FORMAT_S32_LE:
snd_soc_update_bits(codec,
- TABLA_A_CDC_CLK_TX_I2S_CTL,
- 0x20, 0x00);
+ TABLA_A_CDC_CLK_TX_I2S_CTL, 0x20, 0x00);
break;
default:
- pr_err("invalid format\n");
- break;
+ pr_err("%s: invalid TX format %u\n", __func__,
+ params_format(params));
+ return -EINVAL;
}
snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
- 0x07, tx_fs_rate);
+ 0x07, tx_fs_rate_reg_val);
} else {
tabla->dai[dai->id - 1].rate = params_rate(params);
}
- }
- /**
- * TODO: Need to handle case where same RX chain takes 2 or more inputs
- * with varying sample rates
- */
+ break;
- /**
- * If current dai is a rx dai, set sample rate to
- * all the rx paths that are currently not active
- */
- if (dai->id == AIF1_PB || dai->id == AIF2_PB || dai->id == AIF3_PB) {
+ case SNDRV_PCM_STREAM_PLAYBACK:
- rx_state = snd_soc_read(codec,
- TABLA_A_CDC_CLK_RX_B1_CTL);
-
- for (path = 1, shift = 0;
- path <= NUM_INTERPOLATORS; path++, shift++) {
-
- if (!(rx_state & (1 << shift))) {
- rx_fs_reg = TABLA_A_CDC_RX1_B5_CTL
- + (BITS_PER_REG*(path-1));
- snd_soc_update_bits(codec, rx_fs_reg,
- 0xE0, rx_fs_rate);
- if (comp_rx_path[shift] < COMPANDER_MAX)
- tabla->comp_fs[comp_rx_path[shift]]
- = compander_fs;
- }
+ ret = tabla_set_interpolator_rate(dai, rx_fs_rate_reg_val,
+ compander_fs, params_rate(params));
+ if (ret < 0) {
+ pr_err("%s: set decimator rate failed %d\n", __func__,
+ ret);
+ return ret;
}
+
if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
snd_soc_update_bits(codec,
- TABLA_A_CDC_CLK_RX_I2S_CTL,
- 0x20, 0x20);
+ TABLA_A_CDC_CLK_RX_I2S_CTL, 0x20, 0x20);
break;
case SNDRV_PCM_FORMAT_S32_LE:
snd_soc_update_bits(codec,
- TABLA_A_CDC_CLK_RX_I2S_CTL,
- 0x20, 0x00);
+ TABLA_A_CDC_CLK_RX_I2S_CTL, 0x20, 0x00);
break;
default:
- pr_err("invalid format\n");
- break;
+ pr_err("%s: invalid RX format %u\n", __func__,
+ params_format(params));
+ return -EINVAL;
}
snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
- 0x03, (rx_fs_rate >> 0x05));
+ 0x03, (rx_fs_rate_reg_val >> 0x05));
} else {
tabla->dai[dai->id - 1].rate = params_rate(params);
}
- }
+ break;
+ default:
+ pr_err("%s: Invalid stream type %d\n", __func__,
+ substream->stream);
+ return -EINVAL;
+ }
return 0;
}
@@ -4350,30 +4553,6 @@
SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
ARRAY_SIZE(dac1_switch)),
- SND_SOC_DAPM_AIF_IN_E("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
- 0, tabla_codec_enable_slimrx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_AIF_IN_E("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
- 0, tabla_codec_enable_slimrx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_AIF_IN_E("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
- 0, tabla_codec_enable_slimrx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_AIF_IN_E("SLIM RX4", "AIF3 Playback", 0, SND_SOC_NOPM, 0,
- 0, tabla_codec_enable_slimrx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_AIF_IN_E("SLIM RX5", "AIF3 Playback", 0, SND_SOC_NOPM, 0,
- 0, tabla_codec_enable_slimrx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_AIF_IN_E("SLIM RX6", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
- 0, tabla_codec_enable_slimrx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_AIF_IN_E("SLIM RX7", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
- 0, tabla_codec_enable_slimrx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
/* Headphone */
SND_SOC_DAPM_OUTPUT("HEADPHONE"),
SND_SOC_DAPM_PGA_E("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
@@ -4654,54 +4833,15 @@
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX1", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
- 0, tabla_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, 0, 0, &sb_tx2_mux),
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX2", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
- 0, tabla_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, 0, 0, &sb_tx3_mux),
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX3", "AIF3 Capture", 0, SND_SOC_NOPM, 0,
- 0, tabla_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, 0, 0, &sb_tx4_mux),
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX4", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
- 0, tabla_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX5", "AIF3 Capture", 0, SND_SOC_NOPM, 0,
- 0, tabla_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX6", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
- 0, tabla_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX7", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
- 0, tabla_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX8", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
- 0, tabla_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, 0, 0, &sb_tx9_mux),
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX9", "AIF1 Capture", NULL, SND_SOC_NOPM,
- 0, 0, tabla_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, 0, 0, &sb_tx10_mux),
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX10", "AIF1 Capture", NULL, SND_SOC_NOPM,
- 0, 0, tabla_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
/* Digital Mic Inputs */
SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
@@ -7560,6 +7700,13 @@
// snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
// ARRAY_SIZE(tabla_dapm_widgets));
+
+ snd_soc_dapm_new_controls(dapm, tabla_dapm_aif_in_widgets,
+ ARRAY_SIZE(tabla_dapm_aif_in_widgets));
+
+ snd_soc_dapm_new_controls(dapm, tabla_dapm_aif_out_widgets,
+ ARRAY_SIZE(tabla_dapm_aif_out_widgets));
+
if (TABLA_IS_1_X(control->version))
snd_soc_dapm_new_controls(dapm, tabla_1_x_dapm_widgets,
ARRAY_SIZE(tabla_1_x_dapm_widgets));
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index 391c5f3..6685ce5 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -850,7 +850,7 @@
static void msm_mi2s_shutdown(struct snd_pcm_substream *substream)
{
if (mi2s_bit_clk) {
- clk_disable(mi2s_bit_clk);
+ clk_disable_unprepare(mi2s_bit_clk);
clk_put(mi2s_bit_clk);
mi2s_bit_clk = NULL;
}
@@ -892,7 +892,7 @@
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);
+ ret = clk_prepare_enable(mi2s_bit_clk);
if (IS_ERR_VALUE(ret)) {
pr_err("Unable to enable mi2s_bit_clk\n");
clk_put(mi2s_bit_clk);
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 2455128..c894921 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -34,6 +34,13 @@
#include "msm-compr-q6.h"
#include "msm-pcm-routing.h"
+#define COMPRE_CAPTURE_NUM_PERIODS 16
+/* Allocate the worst case frame size for compressed audio */
+#define COMPRE_CAPTURE_HEADER_SIZE (sizeof(struct snd_compr_audio_info))
+#define COMPRE_CAPTURE_MAX_FRAME_SIZE (6144)
+#define COMPRE_CAPTURE_PERIOD_SIZE (COMPRE_CAPTURE_MAX_FRAME_SIZE + \
+ COMPRE_CAPTURE_HEADER_SIZE)
+
struct snd_msm {
struct msm_audio *prtd;
unsigned volume;
@@ -42,6 +49,27 @@
static struct audio_locks the_locks;
+static struct snd_pcm_hardware msm_compr_hardware_capture = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 8,
+ .buffer_bytes_max =
+ COMPRE_CAPTURE_PERIOD_SIZE * COMPRE_CAPTURE_NUM_PERIODS ,
+ .period_bytes_min = COMPRE_CAPTURE_PERIOD_SIZE,
+ .period_bytes_max = COMPRE_CAPTURE_PERIOD_SIZE,
+ .periods_min = COMPRE_CAPTURE_NUM_PERIODS,
+ .periods_max = COMPRE_CAPTURE_NUM_PERIODS,
+ .fifo_size = 0,
+};
+
static struct snd_pcm_hardware msm_compr_hardware_playback = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -81,7 +109,9 @@
struct snd_pcm_substream *substream = prtd->substream;
struct snd_pcm_runtime *runtime = substream->runtime;
struct audio_aio_write_param param;
+ struct audio_aio_read_param read_param;
struct audio_buffer *buf = NULL;
+ uint32_t *ptrmem = (uint32_t *)payload;
int i = 0;
pr_debug("%s opcode =%08x\n", __func__, opcode);
@@ -138,9 +168,53 @@
prtd->cmd_ack = 1;
wake_up(&the_locks.eos_wait);
break;
+ case ASM_DATA_EVENT_READ_DONE: {
+ pr_debug("ASM_DATA_EVENT_READ_DONE\n");
+ pr_debug("buf = %p, data = 0x%X, *data = %p,\n"
+ "prtd->pcm_irq_pos = %d\n",
+ prtd->audio_client->port[OUT].buf,
+ *(uint32_t *)prtd->audio_client->port[OUT].buf->data,
+ prtd->audio_client->port[OUT].buf->data,
+ prtd->pcm_irq_pos);
+
+ memcpy(prtd->audio_client->port[OUT].buf->data +
+ prtd->pcm_irq_pos, (ptrmem + 2),
+ COMPRE_CAPTURE_HEADER_SIZE);
+ pr_debug("buf = %p, updated data = 0x%X, *data = %p\n",
+ prtd->audio_client->port[OUT].buf,
+ *(uint32_t *)(prtd->audio_client->port[OUT].buf->data +
+ prtd->pcm_irq_pos),
+ prtd->audio_client->port[OUT].buf->data);
+ if (!atomic_read(&prtd->start))
+ break;
+ pr_debug("frame size=%d, buffer = 0x%X\n", ptrmem[2],
+ ptrmem[1]);
+ if (ptrmem[2] > COMPRE_CAPTURE_MAX_FRAME_SIZE) {
+ pr_err("Frame length exceeded the max length");
+ break;
+ }
+ buf = prtd->audio_client->port[OUT].buf;
+ pr_debug("pcm_irq_pos=%d, buf[0].phys = 0x%X\n",
+ prtd->pcm_irq_pos, (uint32_t)buf[0].phys);
+ read_param.len = prtd->pcm_count - COMPRE_CAPTURE_HEADER_SIZE ;
+ read_param.paddr = (unsigned long)(buf[0].phys) +
+ prtd->pcm_irq_pos + COMPRE_CAPTURE_HEADER_SIZE;
+ prtd->pcm_irq_pos += prtd->pcm_count;
+
+ if (atomic_read(&prtd->start))
+ snd_pcm_period_elapsed(substream);
+
+ q6asm_async_read(prtd->audio_client, &read_param);
+ break;
+ }
case APR_BASIC_RSP_RESULT: {
switch (payload[0]) {
case ASM_SESSION_CMD_RUN: {
+ if (substream->stream
+ != SNDRV_PCM_STREAM_PLAYBACK) {
+ atomic_set(&prtd->start, 1);
+ break;
+ }
if (!atomic_read(&prtd->pending_buffer))
break;
pr_debug("%s:writing %d bytes"
@@ -230,6 +304,9 @@
pr_debug("compressd playback, no need to send"
" the decoder params\n");
break;
+ case SND_AUDIOCODEC_DTS_PASS_THROUGH:
+ pr_debug("compressd DTS playback,dont send the decoder params\n");
+ break;
case SND_AUDIOCODEC_WMA:
pr_debug("SND_AUDIOCODEC_WMA\n");
memset(&wma_cfg, 0x0, sizeof(struct asm_wma_cfg));
@@ -276,6 +353,16 @@
if (ret < 0)
pr_err("%s: CMD Format block failed\n", __func__);
break;
+ case SND_AUDIOCODEC_DTS:
+ case SND_AUDIOCODEC_DTS_LBR:
+ pr_debug("SND_AUDIOCODEC_DTS\n");
+ ret = q6asm_media_format_block(prtd->audio_client,
+ compr->codec);
+ if (ret < 0) {
+ pr_err("%s: CMD Format block failed\n", __func__);
+ return ret;
+ }
+ break;
default:
return -EINVAL;
}
@@ -286,6 +373,44 @@
return 0;
}
+static int msm_compr_capture_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct compr_audio *compr = runtime->private_data;
+ struct msm_audio *prtd = &compr->prtd;
+ struct audio_buffer *buf = prtd->audio_client->port[OUT].buf;
+ struct audio_aio_read_param read_param;
+ int ret = 0;
+ int i;
+ prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+ prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+ prtd->pcm_irq_pos = 0;
+
+ /* rate and channels are sent to audio driver */
+ prtd->samp_rate = runtime->rate;
+ prtd->channel_mode = runtime->channels;
+
+ if (prtd->enabled)
+ return ret;
+ read_param.len = prtd->pcm_count - COMPRE_CAPTURE_HEADER_SIZE;
+ pr_debug("%s: Samp_rate = %d, Channel = %d, pcm_size = %d,\n"
+ "pcm_count = %d, periods = %d\n",
+ __func__, prtd->samp_rate, prtd->channel_mode,
+ prtd->pcm_size, prtd->pcm_count, runtime->periods);
+
+ for (i = 0; i < runtime->periods; i++) {
+ read_param.uid = i;
+ read_param.paddr = ((unsigned long)(buf[i].phys) +
+ COMPRE_CAPTURE_HEADER_SIZE);
+ q6asm_async_read(prtd->audio_client, &read_param);
+ }
+ prtd->periods = runtime->periods;
+
+ prtd->enabled = 1;
+
+ return ret;
+}
+
static int msm_compr_trigger(struct snd_pcm_substream *substream, int cmd)
{
int ret = 0;
@@ -298,8 +423,17 @@
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
prtd->pcm_irq_pos = 0;
- if (compr->info.codec_param.codec.id ==
- SND_AUDIOCODEC_AC3_PASS_THROUGH) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (compr->info.codec_param.codec.id ==
+ SND_AUDIOCODEC_AC3_PASS_THROUGH ||
+ compr->info.codec_param.codec.id ==
+ SND_AUDIOCODEC_DTS_PASS_THROUGH) {
+ msm_pcm_routing_reg_psthr_stream(
+ soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream,
+ 1);
+ }
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
msm_pcm_routing_reg_psthr_stream(
soc_prtd->dai_link->be_id,
prtd->session_id, substream->stream, 1);
@@ -312,11 +446,19 @@
break;
case SNDRV_PCM_TRIGGER_STOP:
pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
- if (compr->info.codec_param.codec.id ==
- SND_AUDIOCODEC_AC3_PASS_THROUGH) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (compr->info.codec_param.codec.id ==
+ SND_AUDIOCODEC_AC3_PASS_THROUGH) {
+ msm_pcm_routing_reg_psthr_stream(
+ soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream,
+ 0);
+ }
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
msm_pcm_routing_reg_psthr_stream(
soc_prtd->dai_link->be_id,
- prtd->session_id, substream->stream, 0);
+ prtd->session_id, substream->stream,
+ 0);
}
atomic_set(&prtd->start, 0);
break;
@@ -349,6 +491,9 @@
compr->info.compr_cap.codecs[2] = SND_AUDIOCODEC_AC3_PASS_THROUGH;
compr->info.compr_cap.codecs[3] = SND_AUDIOCODEC_WMA;
compr->info.compr_cap.codecs[4] = SND_AUDIOCODEC_WMA_PRO;
+ compr->info.compr_cap.codecs[5] = SND_AUDIOCODEC_DTS;
+ compr->info.compr_cap.codecs[6] = SND_AUDIOCODEC_DTS_LBR;
+ compr->info.compr_cap.codecs[7] = SND_AUDIOCODEC_DTS_PASS_THROUGH;
/* Add new codecs here */
}
@@ -370,10 +515,6 @@
.rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
};
- /* Capture path */
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- return -EINVAL;
-
pr_debug("%s\n", __func__);
compr = kzalloc(sizeof(struct compr_audio), GFP_KERNEL);
if (compr == NULL) {
@@ -389,13 +530,18 @@
kfree(prtd);
return -ENOMEM;
}
- runtime->hw = msm_compr_hardware_playback;
pr_info("%s: session ID %d\n", __func__, prtd->audio_client->session);
prtd->session_id = prtd->audio_client->session;
- prtd->cmd_ack = 1;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ runtime->hw = msm_compr_hardware_playback;
+ prtd->cmd_ack = 1;
+ } else {
+ runtime->hw = msm_compr_hardware_capture;
+ }
+
ret = snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
@@ -410,7 +556,8 @@
prtd->dsp_cnt = 0;
atomic_set(&prtd->pending_buffer, 1);
- compr->codec = FORMAT_MP3;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ compr->codec = FORMAT_MP3;
populate_codec_list(compr, runtime);
runtime->private_data = compr;
compressed_audio.prtd = &compr->prtd;
@@ -473,6 +620,27 @@
return 0;
}
+static int msm_compr_capture_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+ struct compr_audio *compr = runtime->private_data;
+ struct msm_audio *prtd = &compr->prtd;
+ int dir = OUT;
+
+ pr_debug("%s\n", __func__);
+ atomic_set(&prtd->pending_buffer, 0);
+ q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+ q6asm_audio_client_buf_free_contiguous(dir,
+ prtd->audio_client);
+ msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+ SNDRV_PCM_STREAM_CAPTURE);
+ q6asm_audio_client_free(prtd->audio_client);
+ kfree(prtd);
+
+ return 0;
+}
+
static int msm_compr_close(struct snd_pcm_substream *substream)
{
int ret = 0;
@@ -480,7 +648,7 @@
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
ret = msm_compr_playback_close(substream);
else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- ret = EINVAL;
+ ret = msm_compr_capture_close(substream);
return ret;
}
static int msm_compr_prepare(struct snd_pcm_substream *substream)
@@ -490,7 +658,7 @@
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
ret = msm_compr_playback_prepare(substream);
else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- ret = EINVAL;
+ ret = msm_compr_capture_prepare(substream);
return ret;
}
@@ -504,7 +672,10 @@
if (prtd->pcm_irq_pos >= prtd->pcm_size)
prtd->pcm_irq_pos = 0;
- pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
+ pr_debug("%s: pcm_irq_pos = %d, pcm_size = %d, sample_bits = %d,\n"
+ "frame_bits = %d\n", __func__, prtd->pcm_irq_pos,
+ prtd->pcm_size, runtime->sample_bits,
+ runtime->frame_bits);
return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
}
@@ -546,28 +717,45 @@
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dir = IN;
else
- return -EINVAL;
+ dir = OUT;
- switch (compr->info.codec_param.codec.id) {
- case SND_AUDIOCODEC_AC3_PASS_THROUGH:
- ret = q6asm_open_write_compressed(prtd->audio_client,
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ switch (compr->info.codec_param.codec.id) {
+ case SND_AUDIOCODEC_AC3_PASS_THROUGH:
+ case SND_AUDIOCODEC_DTS_PASS_THROUGH:
+ ret = q6asm_open_write_compressed(prtd->audio_client,
compr->codec);
+
+ if (ret < 0) {
+ pr_err("%s: Session out open failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+ break;
+ default:
+ ret = q6asm_open_write(prtd->audio_client,
+ compr->codec);
+ if (ret < 0) {
+ pr_err("%s: Session out open failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+ msm_pcm_routing_reg_phy_stream(
+ soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream);
+
+ break;
+ }
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ ret = q6asm_open_read_compressed(prtd->audio_client,
+ compr->codec);
+
if (ret < 0) {
pr_err("%s: compressed Session out open failed\n",
- __func__);
+ __func__);
return -ENOMEM;
}
- break;
- default:
- ret = q6asm_open_write(prtd->audio_client, compr->codec);
- if (ret < 0) {
- pr_err("%s: Session out open failed\n", __func__);
- return -ENOMEM;
- }
- msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
- prtd->session_id, substream->stream);
-
- break;
}
ret = q6asm_set_io_mode(prtd->audio_client, ASYNC_IO_MODE);
if (ret < 0) {
@@ -586,13 +774,17 @@
}
buf = prtd->audio_client->port[dir].buf;
- pr_debug("%s:buf = %p\n", __func__, buf);
dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
dma_buf->dev.dev = substream->pcm->card->dev;
dma_buf->private_data = NULL;
dma_buf->area = buf[0].data;
dma_buf->addr = buf[0].phys;
dma_buf->bytes = runtime->hw.buffer_bytes_max;
+
+ pr_debug("%s: buf[%p]dma_buf->area[%p]dma_buf->addr[%p]\n"
+ "dma_buf->bytes[%d]\n", __func__,
+ (void *)buf, (void *)dma_buf->area,
+ (void *)dma_buf->addr, dma_buf->bytes);
if (!dma_buf->area)
return -ENOMEM;
@@ -674,6 +866,18 @@
pr_debug("SND_AUDIOCODEC_WMA_PRO\n");
compr->codec = FORMAT_WMA_V10PRO;
break;
+ case SND_AUDIOCODEC_DTS_PASS_THROUGH:
+ pr_debug("SND_AUDIOCODEC_DTS_PASS_THROUGH\n");
+ compr->codec = FORMAT_DTS;
+ break;
+ case SND_AUDIOCODEC_DTS:
+ pr_debug("SND_AUDIOCODEC_DTS\n");
+ compr->codec = FORMAT_DTS;
+ break;
+ case SND_AUDIOCODEC_DTS_LBR:
+ pr_debug("SND_AUDIOCODEC_DTS\n");
+ compr->codec = FORMAT_DTS_LBR;
+ break;
default:
pr_debug("FORMAT_LINEAR_PCM\n");
compr->codec = FORMAT_LINEAR_PCM;
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 8a49f1b..be0951c 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -176,6 +176,17 @@
.rate_min = 8000,
.rate_max = 48000,
},
+ .capture = {
+ .stream_name = "MultiMedia4 Capture",
+ .aif_name = "MM_UL4",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
.ops = &msm_fe_Multimedia_dai_ops,
.name = "MultiMedia4",
},
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index b3e5120..147316e 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -40,9 +40,14 @@
union afe_port_config port_config;
};
+struct msm_dai_q6_mi2s_dai_config {
+ u16 pdata_mi2s_lines;
+ struct msm_dai_q6_dai_data mi2s_dai_data;
+};
+
struct msm_dai_q6_mi2s_dai_data {
- struct msm_dai_q6_dai_data tx_dai;
- struct msm_dai_q6_dai_data rx_dai;
+ struct msm_dai_q6_mi2s_dai_config tx_dai;
+ struct msm_dai_q6_mi2s_dai_config rx_dai;
struct snd_pcm_hw_constraint_list rate_constraint;
struct snd_pcm_hw_constraint_list bitwidth_constraint;
};
@@ -86,8 +91,8 @@
static const char *mi2s_format[] = {
"LPCM",
"Compr",
- "60958-LPCM",
- "60958-Compr"};
+ "LPCM-60958",
+ "Compr-60958"};
static const struct soc_enum mi2s_config_enum[] = {
SOC_ENUM_SINGLE_EXT(4, mi2s_format),
@@ -143,21 +148,63 @@
{
struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
dev_get_drvdata(dai->dev);
- struct msm_dai_q6_dai_data *dai_data =
+ struct msm_dai_q6_mi2s_dai_config *mi2s_dai_config =
(substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
&mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
+ struct msm_dai_q6_dai_data *dai_data = &mi2s_dai_config->mi2s_dai_data;
dai_data->channels = params_channels(params);
switch (dai_data->channels) {
- case 2:
- dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
+ case 8:
+ case 7:
+ if (mi2s_dai_config->pdata_mi2s_lines < AFE_I2S_8CHS)
+ goto error_invalid_data;
+ dai_data->port_config.mi2s.line = AFE_I2S_8CHS;
break;
+ case 6:
+ case 5:
+ if (mi2s_dai_config->pdata_mi2s_lines < AFE_I2S_6CHS)
+ goto error_invalid_data;
+ dai_data->port_config.mi2s.line = AFE_I2S_6CHS;
+ break;
+ case 4:
+ case 3:
+ if (mi2s_dai_config->pdata_mi2s_lines < AFE_I2S_QUAD01)
+ goto error_invalid_data;
+ if (mi2s_dai_config->pdata_mi2s_lines == AFE_I2S_QUAD23)
+ dai_data->port_config.mi2s.line =
+ mi2s_dai_config->pdata_mi2s_lines;
+ else
+ dai_data->port_config.mi2s.line = AFE_I2S_QUAD01;
+ break;
+ case 2:
case 1:
- dai_data->port_config.mi2s.channel = MSM_AFE_MONO;
+ if (mi2s_dai_config->pdata_mi2s_lines < AFE_I2S_SD0)
+ goto error_invalid_data;
+ switch (mi2s_dai_config->pdata_mi2s_lines) {
+ case AFE_I2S_SD0:
+ case AFE_I2S_SD1:
+ case AFE_I2S_SD2:
+ case AFE_I2S_SD3:
+ dai_data->port_config.mi2s.line =
+ mi2s_dai_config->pdata_mi2s_lines;
+ break;
+ case AFE_I2S_QUAD01:
+ case AFE_I2S_6CHS:
+ case AFE_I2S_8CHS:
+ dai_data->port_config.mi2s.line = AFE_I2S_SD0;
+ break;
+ case AFE_I2S_QUAD23:
+ dai_data->port_config.mi2s.line = AFE_I2S_SD2;
+ break;
+ }
+ if (dai_data->channels == 2)
+ dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
+ else
+ dai_data->port_config.mi2s.channel = MSM_AFE_MONO;
break;
default:
- pr_warn("greater than stereo has not been validated");
- break;
+ goto error_invalid_data;
}
dai_data->rate = params_rate(params);
dai_data->port_config.mi2s.bitwidth = 16;
@@ -166,7 +213,14 @@
mi2s_dai_data->rate_constraint.list = &dai_data->rate;
mi2s_dai_data->bitwidth_constraint.list = &dai_data->bitwidth;
}
+
+ pr_debug("%s: dai_data->channels = %d, line = %d\n", __func__,
+ dai_data->channels, dai_data->port_config.mi2s.line);
return 0;
+error_invalid_data:
+ pr_err("%s: dai_data->channels = %d, line = %d\n", __func__,
+ dai_data->channels, dai_data->port_config.mi2s.line);
+ return -EINVAL;
}
static int msm_dai_q6_mi2s_get_lineconfig(u16 sd_lines, u16 *config_ptr,
@@ -276,7 +330,9 @@
}
if (ch_cnt) {
- dai_data->rx_dai.port_config.mi2s.line = sdline_config;
+ dai_data->rx_dai.mi2s_dai_data.port_config.mi2s.line =
+ sdline_config;
+ dai_data->rx_dai.pdata_mi2s_lines = sdline_config;
dai_driver->playback.channels_min = 1;
dai_driver->playback.channels_max = ch_cnt << 1;
} else {
@@ -292,7 +348,9 @@
}
if (ch_cnt) {
- dai_data->tx_dai.port_config.mi2s.line = sdline_config;
+ dai_data->tx_dai.mi2s_dai_data.port_config.mi2s.line =
+ sdline_config;
+ dai_data->tx_dai.pdata_mi2s_lines = sdline_config;
dai_driver->capture.channels_min = 1;
dai_driver->capture.channels_max = ch_cnt << 1;
} else {
@@ -301,8 +359,8 @@
}
dev_info(&pdev->dev, "%s: playback sdline %x capture sdline %x\n",
- __func__, dai_data->rx_dai.port_config.mi2s.line,
- dai_data->tx_dai.port_config.mi2s.line);
+ __func__, dai_data->rx_dai.pdata_mi2s_lines,
+ dai_data->tx_dai.pdata_mi2s_lines);
dev_info(&pdev->dev, "%s: playback ch_max %d capture ch_mx %d\n",
__func__, dai_driver->playback.channels_max,
dai_driver->capture.channels_max);
@@ -315,8 +373,10 @@
struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
dev_get_drvdata(dai->dev);
- if (test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask) ||
- test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask)) {
+ if (test_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask) ||
+ test_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->tx_dai.mi2s_dai_data.status_mask)) {
dev_err(dai->dev, "%s: err chg i2s mode while dai running",
__func__);
return -EPERM;
@@ -324,12 +384,12 @@
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
- mi2s_dai_data->rx_dai.port_config.mi2s.ws = 1;
- mi2s_dai_data->tx_dai.port_config.mi2s.ws = 1;
+ mi2s_dai_data->rx_dai.mi2s_dai_data.port_config.mi2s.ws = 1;
+ mi2s_dai_data->tx_dai.mi2s_dai_data.port_config.mi2s.ws = 1;
break;
case SND_SOC_DAIFMT_CBM_CFM:
- mi2s_dai_data->rx_dai.port_config.mi2s.ws = 0;
- mi2s_dai_data->tx_dai.port_config.mi2s.ws = 0;
+ mi2s_dai_data->rx_dai.mi2s_dai_data.port_config.mi2s.ws = 0;
+ mi2s_dai_data->tx_dai.mi2s_dai_data.port_config.mi2s.ws = 0;
break;
default:
return -EINVAL;
@@ -345,7 +405,8 @@
dev_get_drvdata(dai->dev);
struct msm_dai_q6_dai_data *dai_data =
(substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
- &mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
+ &mi2s_dai_data->rx_dai.mi2s_dai_data :
+ &mi2s_dai_data->tx_dai.mi2s_dai_data);
int rc = 0;
if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
@@ -364,7 +425,8 @@
dev_get_drvdata(dai->dev);
struct msm_dai_q6_dai_data *dai_data =
(substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
- &mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
+ &mi2s_dai_data->rx_dai.mi2s_dai_data :
+ &mi2s_dai_data->tx_dai.mi2s_dai_data);
u16 port_id = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
MI2S_RX : MI2S_TX);
int rc = 0;
@@ -406,7 +468,8 @@
dev_get_drvdata(dai->dev);
struct msm_dai_q6_dai_data *dai_data =
(substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
- &mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
+ &mi2s_dai_data->rx_dai.mi2s_dai_data :
+ &mi2s_dai_data->tx_dai.mi2s_dai_data);
u16 port_id = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
MI2S_RX : MI2S_TX);
int rc = 0;
@@ -418,8 +481,10 @@
clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
}
- if (!test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask) &&
- !test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask)) {
+ if (!test_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask) &&
+ !test_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask)) {
mi2s_dai_data->rate_constraint.list = NULL;
mi2s_dai_data->bitwidth_constraint.list = NULL;
}
@@ -1268,9 +1333,9 @@
struct snd_kcontrol *kcontrol = NULL;
int rc = 0;
- if (mi2s_dai_data->rx_dai.port_config.mi2s.line) {
+ if (mi2s_dai_data->rx_dai.mi2s_dai_data.port_config.mi2s.line) {
kcontrol = snd_ctl_new1(&mi2s_config_controls[0],
- &mi2s_dai_data->rx_dai);
+ &mi2s_dai_data->rx_dai.mi2s_dai_data);
rc = snd_ctl_add(dai->card->snd_card, kcontrol);
if (IS_ERR_VALUE(rc)) {
@@ -1279,10 +1344,10 @@
}
}
- if (mi2s_dai_data->tx_dai.port_config.mi2s.line) {
+ if (mi2s_dai_data->tx_dai.mi2s_dai_data.port_config.mi2s.line) {
rc = snd_ctl_add(dai->card->snd_card,
- snd_ctl_new1(&mi2s_config_controls[2],
- &mi2s_dai_data->tx_dai));
+ snd_ctl_new1(&mi2s_config_controls[2],
+ &mi2s_dai_data->tx_dai.mi2s_dai_data));
if (IS_ERR_VALUE(rc)) {
if (kcontrol)
@@ -1302,19 +1367,21 @@
int rc;
/* If AFE port is still up, close it */
- if (test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask)) {
+ if (test_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask)) {
rc = afe_close(MI2S_RX); /* can block */
if (IS_ERR_VALUE(rc))
dev_err(dai->dev, "fail to close MI2S_RX port\n");
clear_bit(STATUS_PORT_STARTED,
- mi2s_dai_data->rx_dai.status_mask);
+ mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask);
}
- if (test_bit(STATUS_PORT_STARTED, mi2s_dai_data->tx_dai.status_mask)) {
+ if (test_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->tx_dai.mi2s_dai_data.status_mask)) {
rc = afe_close(MI2S_TX); /* can block */
if (IS_ERR_VALUE(rc))
dev_err(dai->dev, "fail to close MI2S_TX port\n");
clear_bit(STATUS_PORT_STARTED,
- mi2s_dai_data->tx_dai.status_mask);
+ mi2s_dai_data->tx_dai.mi2s_dai_data.status_mask);
}
kfree(mi2s_dai_data);
snd_soc_unregister_dai(dai->dev);
@@ -1966,6 +2033,8 @@
return 0;
err_pdata:
+
+ dev_err(&pdev->dev, "fail to msm_dai_q6_mi2s_dev_probe\n");
kfree(dai_data);
rtn:
return rc;
diff --git a/sound/soc/msm/msm-pcm-q6.c b/sound/soc/msm/msm-pcm-q6.c
index 39ce436..168cf97 100644
--- a/sound/soc/msm/msm-pcm-q6.c
+++ b/sound/soc/msm/msm-pcm-q6.c
@@ -532,12 +532,15 @@
int dir = OUT;
pr_debug("%s\n", __func__);
- q6asm_cmd(prtd->audio_client, CMD_CLOSE);
- q6asm_audio_client_buf_free_contiguous(dir,
+ if (prtd->audio_client) {
+ q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+ q6asm_audio_client_buf_free_contiguous(dir,
prtd->audio_client);
+ q6asm_audio_client_free(prtd->audio_client);
+ }
+
msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
- SNDRV_PCM_STREAM_CAPTURE);
- q6asm_audio_client_free(prtd->audio_client);
+ SNDRV_PCM_STREAM_CAPTURE);
kfree(prtd);
return 0;
@@ -638,7 +641,7 @@
if (ret < 0) {
pr_err("%s: q6asm_open_read failed\n", __func__);
q6asm_audio_client_free(prtd->audio_client);
- kfree(prtd);
+ prtd->audio_client = NULL;
return -ENOMEM;
}
}
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 239c904..387fe44 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -1352,6 +1352,13 @@
msm_routing_put_audio_mixer),
};
+
+static const struct snd_kcontrol_new mmul4_mixer_controls[] = {
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -1983,6 +1990,7 @@
SND_SOC_DAPM_AIF_IN("VOIP_DL", "VoIP Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0),
@@ -2080,6 +2088,8 @@
mmul1_mixer_controls, ARRAY_SIZE(mmul1_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia2 Mixer", SND_SOC_NOPM, 0, 0,
mmul2_mixer_controls, ARRAY_SIZE(mmul2_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia4 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul4_mixer_controls, ARRAY_SIZE(mmul4_mixer_controls)),
SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -2247,6 +2257,7 @@
{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
{"MultiMedia1 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"},
+ {"MultiMedia4 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
{"MultiMedia1 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
@@ -2276,6 +2287,7 @@
{"MM_UL1", NULL, "MultiMedia1 Mixer"},
{"MultiMedia2 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MM_UL2", NULL, "MultiMedia2 Mixer"},
+ {"MM_UL4", NULL, "MultiMedia4 Mixer"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 50011a1..f39a227 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -737,6 +737,9 @@
cnt++;
}
ac->port[dir].max_buf_cnt = cnt;
+
+ pr_debug("%s ac->port[%d].max_buf_cnt[%d]\n", __func__, dir,
+ ac->port[dir].max_buf_cnt);
mutex_unlock(&ac->cmd_lock);
rc = q6asm_memory_map(ac, buf[0].phys, dir, bufsz, cnt);
if (rc < 0) {
@@ -857,6 +860,7 @@
case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
case ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED:
+ case ASM_STREAM_CMD_OPEN_READ_COMPRESSED:
if (atomic_read(&ac->cmd_state)) {
atomic_set(&ac->cmd_state, 0);
wake_up(&ac->cmd_wait);
@@ -1260,6 +1264,42 @@
return -EINVAL;
}
+int q6asm_open_read_compressed(struct audio_client *ac, uint32_t format)
+{
+ int rc = 0x00;
+ struct asm_stream_cmd_open_read_compressed open;
+#ifdef CONFIG_DEBUG_FS
+ in_cont_index = 0;
+#endif
+ if ((ac == NULL) || (ac->apr == NULL)) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s:session[%d]", __func__, ac->session);
+
+ q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+ open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ_COMPRESSED;
+ /* hardcoded as following*/
+ open.frame_per_buf = 1;
+ open.uMode = 0;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+ if (rc < 0) {
+ pr_err("open failed op[0x%x]rc[%d]\n", open.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for OPEN_READ_COMPRESSED rc[%d]\n",
+ __func__, rc);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format)
{
int rc = 0x00;
@@ -1289,6 +1329,9 @@
case FORMAT_DTS:
open.format = DTS;
break;
+ case FORMAT_DTS_LBR:
+ open.format = DTS_LBR;
+ break;
case FORMAT_AAC:
open.format = MPEG4_AAC;
break;
@@ -1372,6 +1415,12 @@
case FORMAT_MP3:
open.format = MP3;
break;
+ case FORMAT_DTS:
+ open.format = DTS;
+ break;
+ case FORMAT_DTS_LBR:
+ open.format = DTS_LBR;
+ break;
default:
pr_err("%s: Invalid format[%d]\n", __func__, format);
goto fail_cmd;
@@ -2263,6 +2312,12 @@
case FORMAT_MP3:
fmt.format = MP3;
break;
+ case FORMAT_DTS:
+ fmt.format = DTS;
+ break;
+ case FORMAT_DTS_LBR:
+ fmt.format = DTS_LBR;
+ break;
default:
pr_err("Invalid format[%d]\n", format);
goto fail_cmd;