Merge "cma: Remove __init annotations from data structures"
diff --git a/Documentation/devicetree/bindings/arm/msm/ipc-spinlock.txt b/Documentation/devicetree/bindings/arm/msm/ipc-spinlock.txt
index c71b190..24dbb4b 100644
--- a/Documentation/devicetree/bindings/arm/msm/ipc-spinlock.txt
+++ b/Documentation/devicetree/bindings/arm/msm/ipc-spinlock.txt
@@ -1,14 +1,27 @@
Qualcomm Interprocessor Communication Spinlock
+--Dedicated Hardware Implementation--
Required properties:
-- compatible : should be "qcom,ipc-spinlock"
+- compatible : should be "qcom,ipc-spinlock-sfpb"
- reg : the location and size of the spinlock hardware
- qcom,num-locks : the number of locks supported
Example:
qcom,ipc-spinlock@fd484000 {
- compatible = "qcom,ipc-spinlock";
+ compatible = "qcom,ipc-spinlock-sfpb";
reg = <0xfd484000 0x1000>;
qcom,num-locks = <32>;
};
+
+--LDREX Implementation--
+Required properties:
+- compatible : should be "qcom,ipc-spinlock-ldrex"
+- reg : the location and size of the shared lock memory
+
+Example:
+
+ qcom,ipc-spinlock@fa00000 {
+ compatible = "qcom,ipc-spinlock-ldrex";
+ reg = <0xfa00000 0x200000>;
+ };
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index ed18cae..3a9b770 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -63,27 +63,6 @@
8 - SIGSEGV faults
16 - SIGBUS faults
-config DEBUG_RODATA
- bool "Write protect kernel text section"
- default n
- depends on DEBUG_KERNEL && MMU
- ---help---
- Mark the kernel text section as write-protected in the pagetables,
- in order to catch accidental (and incorrect) writes to such const
- data. This will cause the size of the kernel, plus up to 4MB, to
- be mapped as pages instead of sections, which will increase TLB
- pressure.
- If in doubt, say "N".
-
-config DEBUG_RODATA_TEST
- bool "Testcase for the DEBUG_RODATA feature"
- depends on DEBUG_RODATA
- default n
- ---help---
- This option enables a testcase for the DEBUG_RODATA
- feature.
- If in doubt, say "N"
-
# These options are only for real kernel hackers who want to get their hands dirty.
config DEBUG_LL
bool "Kernel low-level debugging functions (read help!)"
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 3533d19..bcf2cc9 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -578,6 +578,11 @@
qcom,bam-producer-pipe-index = <13>;
};
+ qcom,bam_dmux@fc834000 {
+ compatible = "qcom,bam_dmux";
+ reg = <0xfc834000 0x7000>;
+ interrupts = <0 29 1>;
+ };
};
&gdsc_venus {
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 68fed68..6e2719b 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -380,7 +380,7 @@
};
&usb3 {
- qcom,charging-disabled;
+ qcom,otg-capability;
};
&pm8941_mvs1 {
@@ -708,3 +708,33 @@
};
};
};
+
+&pm8941_chg {
+ status = "ok";
+
+ qcom,chg-charging-disabled;
+
+ qcom,chg-chgr@1000 {
+ status = "ok";
+ };
+
+ qcom,chg-buck@1100 {
+ status = "ok";
+ };
+
+ qcom,chg-usb-chgpth@1300 {
+ status = "ok";
+ };
+
+ qcom,chg-dc-chgpth@1400 {
+ status = "ok";
+ };
+
+ qcom,chg-boost@1500 {
+ status = "ok";
+ };
+
+ qcom,chg-misc@1600 {
+ status = "ok";
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index aed4daf..fc3a1d3 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -111,3 +111,11 @@
<1616000 2908800>,
<2020000 6400000>;
};
+
+&sfpb_spinlock {
+ status = "disable";
+};
+
+&ldrex_spinlock {
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index b0b7677..2c4d5d9 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -1234,6 +1234,18 @@
compatible = "qcom,ssm";
qcom,channel-name = "SSM_RTR";
};
+
+ sfpb_spinlock: qcom,ipc-spinlock@fd484000 {
+ compatible = "qcom,ipc-spinlock-sfpb";
+ reg = <0xfd484000 0x1000>;
+ qcom,num-locks = <32>;
+ };
+
+ ldrex_spinlock: qcom,ipc-spinlock@fa00000 {
+ compatible = "qcom,ipc-spinlock-ldrex";
+ reg = <0xfa00000 0x200000>;
+ status = "disable";
+ };
};
&gdsc_venus {
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index f22fc28..8517605 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -515,6 +515,7 @@
qcom,msm-pcm {
compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <0>;
};
qcom,msm-pcm-routing {
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 2e4f84d..3d710cc 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -45,6 +45,7 @@
CONFIG_MSM_SMD=y
CONFIG_MSM_SMD_PKG4=y
CONFIG_MSM_IPC_LOGGING=y
+CONFIG_MSM_BAM_DMUX=y
CONFIG_MSM_SMP2P=y
CONFIG_MSM_SMP2P_TEST=y
CONFIG_MSM_IPC_ROUTER=y
@@ -108,6 +109,10 @@
CONFIG_BRIDGE_NF_EBTABLES=y
CONFIG_BRIDGE_EBT_BROUTE=y
CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_MD=y
@@ -115,6 +120,8 @@
CONFIG_DM_CRYPT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
+# CONFIG_MSM_RMNET is not set
+CONFIG_MSM_RMNET_BAM=y
CONFIG_WCNSS_CORE=y
CONFIG_WCNSS_CORE_PRONTO=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index d021905..584fe0b 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -16,7 +16,6 @@
#include <asm/shmparam.h>
#include <asm/cachetype.h>
#include <asm/outercache.h>
-#include <asm/rodata.h>
#define CACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT)
diff --git a/arch/arm/include/asm/rodata.h b/arch/arm/include/asm/rodata.h
deleted file mode 100644
index 8c8add8..0000000
--- a/arch/arm/include/asm/rodata.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * arch/arm/include/asm/rodata.h
- *
- * Copyright (C) 2011 Google, Inc.
- *
- * Author: Colin Cross <ccross@android.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#ifndef _ASMARM_RODATA_H
-#define _ASMARM_RODATA_H
-
-#ifndef __ASSEMBLY__
-
-#ifdef CONFIG_DEBUG_RODATA
-
-int set_memory_rw(unsigned long virt, int numpages);
-int set_memory_ro(unsigned long virt, int numpages);
-
-void mark_rodata_ro(void);
-void set_kernel_text_rw(void);
-void set_kernel_text_ro(void);
-#else
-static inline void set_kernel_text_rw(void) { }
-static inline void set_kernel_text_ro(void) { }
-#endif
-
-#endif
-
-#endif
diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c
index bf17145..df0bf0c 100644
--- a/arch/arm/kernel/ftrace.c
+++ b/arch/arm/kernel/ftrace.c
@@ -13,7 +13,6 @@
*/
#include <linux/ftrace.h>
-#include <linux/module.h>
#include <linux/uaccess.h>
#include <asm/cacheflush.h>
@@ -64,20 +63,6 @@
}
#endif
-int ftrace_arch_code_modify_prepare(void)
-{
- set_kernel_text_rw();
- set_all_modules_text_rw();
- return 0;
-}
-
-int ftrace_arch_code_modify_post_process(void)
-{
- set_all_modules_text_ro();
- set_kernel_text_ro();
- return 0;
-}
-
static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr)
{
return arm_gen_branch_link(pc, addr);
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 42ed059..f0b706a 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -412,6 +412,7 @@
select CPU_FREQ_GOV_ONDEMAND
select MSM_PIL
select MSM_RUN_QUEUE_STATS
+ select ARM_HAS_SG_CHAIN
config ARCH_MSM8226
bool "MSM8226"
@@ -438,6 +439,7 @@
select MEMORY_HOLE_CARVEOUT
select DONT_MAP_HOLE_AFTER_MEMBANK0
select MSM_BUS_SCALING
+ select ARM_HAS_SG_CHAIN
endmenu
choice
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 7dc3a0e..8ba1b39 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -53,13 +53,13 @@
* 3) Depending on Frodo version, may need minimum of LVL_NOM
*/
static struct clkctl_acpu_speed acpu_freq_tbl[] = {
- { 0, 19200, CXO, 0, 0, LVL_LOW, 950000, 0 },
- { 1, 300000, PLL0, 4, 2, LVL_LOW, 950000, 4 },
- { 1, 384000, ACPUPLL, 5, 0, LVL_LOW, 950000, 4 },
- { 1, 600000, PLL0, 4, 0, LVL_NOM, 950000, 6 },
- { 1, 787200, ACPUPLL, 5, 0, LVL_NOM, 1050000, 6 },
- { 1, 998400, ACPUPLL, 5, 0, LVL_HIGH, 1050000, 7 },
- { 1, 1190400, ACPUPLL, 5, 0, LVL_HIGH, 1050000, 7 },
+ { 0, 19200, CXO, 0, 0, 1150000, 1150000, 0 },
+ { 1, 300000, PLL0, 4, 2, 1150000, 1150000, 4 },
+ { 1, 384000, ACPUPLL, 5, 0, 1150000, 1150000, 4 },
+ { 1, 600000, PLL0, 4, 0, 1150000, 1150000, 6 },
+ { 1, 787200, ACPUPLL, 5, 0, 1150000, 1150000, 6 },
+ { 0, 998400, ACPUPLL, 5, 0, 1150000, 1150000, 7 },
+ { 0, 1190400, ACPUPLL, 5, 0, 1150000, 1150000, 7 },
{ 0 }
};
@@ -68,7 +68,7 @@
.current_speed = &(struct clkctl_acpu_speed){ 0 },
.bus_scale = &bus_client_pdata,
/* FIXME regulator doesn't support corners yet */
- .vdd_max_cpu = 1050000,
+ .vdd_max_cpu = 1150000,
.vdd_max_mem = 1150000,
.src_clocks = {
[PLL0].name = "gpll0",
diff --git a/arch/arm/mach-msm/acpuclock-cortex.c b/arch/arm/mach-msm/acpuclock-cortex.c
index 4ac1408..febf95a 100644
--- a/arch/arm/mach-msm/acpuclock-cortex.c
+++ b/arch/arm/mach-msm/acpuclock-cortex.c
@@ -329,8 +329,8 @@
max_cpu_khz = acpuclk_init_data->freq_tbl[i].khz;
/* Initialize regulators */
- rc = increase_vdd(acpuclk_init_data->freq_tbl[i].vdd_cpu,
- acpuclk_init_data->freq_tbl[i].vdd_mem);
+ rc = increase_vdd(acpuclk_init_data->vdd_max_cpu,
+ acpuclk_init_data->vdd_max_mem);
if (rc)
goto err_vdd;
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index a1ff607..0b3366c 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -557,4 +557,7 @@
if (!machine_is_apq8064_mtp() && !machine_is_apq8064_liquid())
apq8064_pm8921_chg_pdata.battery_less_hardware = 1;
+
+ if (machine_is_mpq8064_hrd())
+ apq8064_pm8921_chg_pdata.disable_chg_rmvl_wrkarnd = 1;
}
diff --git a/arch/arm/mach-msm/include/mach/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index 5ccdf82..1073266 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.h
@@ -438,6 +438,9 @@
int (*release_resource)(void);
};
+#define A2_MUX_HDR_NAME_V4_PREF "dmux_hdr_v4_"
+#define A2_MUX_HDR_NAME_V6_PREF "dmux_hdr_v6_"
+
enum a2_mux_event_type {
A2_MUX_RECEIVE,
A2_MUX_WRITE_DONE
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index 02272bc..eb44c40 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -19,15 +19,15 @@
#include <linux/rbtree.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
#include <asm/sizes.h>
#include <asm/page.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
#include <mach/socinfo.h>
#include <mach/msm_subsystem_map.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
struct msm_iova_data {
struct rb_node node;
diff --git a/arch/arm/mach-msm/remote_spinlock.c b/arch/arm/mach-msm/remote_spinlock.c
index 4e09a9e..86b068c 100644
--- a/arch/arm/mach-msm/remote_spinlock.c
+++ b/arch/arm/mach-msm/remote_spinlock.c
@@ -196,6 +196,8 @@
/* end swp implementation --------------------------------------------------- */
/* ldrex implementation ----------------------------------------------------- */
+static char *ldrex_compatible_string = "qcom,ipc-spinlock-ldrex";
+
static void __raw_remote_ex_spin_lock(raw_remote_spinlock_t *lock)
{
unsigned long tmp;
@@ -267,7 +269,7 @@
static void *hw_mutex_reg_base;
static DEFINE_MUTEX(hw_map_init_lock);
-static char *compatible_string = "qcom,ipc-spinlock";
+static char *sfpb_compatible_string = "qcom,ipc-spinlock-sfpb";
static int init_hw_mutex(struct device_node *node)
{
@@ -294,7 +296,7 @@
{
struct device_node *node;
- node = of_find_compatible_node(NULL, NULL, compatible_string);
+ node = of_find_compatible_node(NULL, NULL, sfpb_compatible_string);
if (node) {
init_hw_mutex(node);
} else {
@@ -397,6 +399,23 @@
}
+static int dt_node_is_valid(const struct device_node *node)
+{
+ const char *status;
+ int statlen;
+
+ status = of_get_property(node, "status", &statlen);
+ if (status == NULL)
+ return 1;
+
+ if (statlen > 0) {
+ if (!strcmp(status, "okay") || !strcmp(status, "ok"))
+ return 1;
+ }
+
+ return 0;
+}
+
static void initialize_ops(void)
{
struct device_node *node;
@@ -435,23 +454,42 @@
is_hw_lock_type = 1;
break;
case AUTO_MODE:
- node = of_find_compatible_node(NULL, NULL, compatible_string);
- if (node) {
+ /*
+ * of_find_compatible_node() returns a valid pointer even if
+ * the status property is "disabled", so the validity needs
+ * to be checked
+ */
+ node = of_find_compatible_node(NULL, NULL,
+ sfpb_compatible_string);
+ if (node && dt_node_is_valid(node)) {
current_ops.lock = __raw_remote_sfpb_spin_lock;
current_ops.unlock = __raw_remote_sfpb_spin_unlock;
current_ops.trylock = __raw_remote_sfpb_spin_trylock;
current_ops.release = __raw_remote_gen_spin_release;
current_ops.owner = __raw_remote_gen_spin_owner;
is_hw_lock_type = 1;
- } else {
+ break;
+ }
+
+ node = of_find_compatible_node(NULL, NULL,
+ ldrex_compatible_string);
+ if (node && dt_node_is_valid(node)) {
current_ops.lock = __raw_remote_ex_spin_lock;
current_ops.unlock = __raw_remote_ex_spin_unlock;
current_ops.trylock = __raw_remote_ex_spin_trylock;
current_ops.release = __raw_remote_gen_spin_release;
current_ops.owner = __raw_remote_gen_spin_owner;
is_hw_lock_type = 0;
- pr_warn("Falling back to LDREX remote spinlock implementation");
+ break;
}
+
+ current_ops.lock = __raw_remote_ex_spin_lock;
+ current_ops.unlock = __raw_remote_ex_spin_unlock;
+ current_ops.trylock = __raw_remote_ex_spin_trylock;
+ current_ops.release = __raw_remote_gen_spin_release;
+ current_ops.owner = __raw_remote_gen_spin_owner;
+ is_hw_lock_type = 0;
+ pr_warn("Falling back to LDREX remote spinlock implementation");
break;
default:
BUG();
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 6314e94..d177b05 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -7,7 +7,6 @@
obj-$(CONFIG_MMU) += fault-armv.o flush.o idmap.o ioremap.o \
mmap.o pgd.o mmu.o vmregion.o
-obj-$(CONFIG_DEBUG_RODATA) += rodata.o
ifneq ($(CONFIG_MMU),y)
obj-y += nommu.o
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 0ebc2b9..bf59a9d 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -224,7 +224,7 @@
* allocations. This must be the smallest DMA mask in the system,
* so a successful GFP_DMA allocation will always satisfy this.
*/
-u32 arm_dma_limit;
+phys_addr_t arm_dma_limit;
static void __init arm_adjust_dma_zone(unsigned long *size, unsigned long *hole,
unsigned long dma_size)
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
index 8877ddd..21653f2 100644
--- a/arch/arm/mm/mm.h
+++ b/arch/arm/mm/mm.h
@@ -65,9 +65,9 @@
#endif
#ifdef CONFIG_ZONE_DMA
-extern u32 arm_dma_limit;
+extern phys_addr_t arm_dma_limit;
#else
-#define arm_dma_limit ((u32)~0)
+#define arm_dma_limit ((phys_addr_t)~0)
#endif
struct map_desc;
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 8575f78..25cb67c 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -604,53 +604,30 @@
return early_alloc_aligned(sz, sz);
}
-static pte_t * __init early_pte_alloc(pmd_t *pmd)
-{
- if (pmd_none(*pmd) || pmd_bad(*pmd))
- return early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE);
- return pmd_page_vaddr(*pmd);
-}
-
-static void __init early_pte_install(pmd_t *pmd, pte_t *pte, unsigned long prot)
-{
- __pmd_populate(pmd, __pa(pte), prot);
- BUG_ON(pmd_bad(*pmd));
-}
-
-#ifdef CONFIG_HIGHMEM
-static pte_t * __init early_pte_alloc_and_install(pmd_t *pmd,
- unsigned long addr, unsigned long prot)
+static pte_t * __init early_pte_alloc(pmd_t *pmd, unsigned long addr, unsigned long prot)
{
if (pmd_none(*pmd)) {
- pte_t *pte = early_pte_alloc(pmd);
- early_pte_install(pmd, pte, prot);
+ pte_t *pte = early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE);
+ __pmd_populate(pmd, __pa(pte), prot);
}
BUG_ON(pmd_bad(*pmd));
return pte_offset_kernel(pmd, addr);
}
-#endif
static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
unsigned long end, unsigned long pfn,
const struct mem_type *type)
{
- pte_t *start_pte = early_pte_alloc(pmd);
- pte_t *pte = start_pte + pte_index(addr);
-
- /* If replacing a section mapping, the whole section must be replaced */
- BUG_ON(pmd_bad(*pmd) && ((addr | end) & ~PMD_MASK));
-
+ pte_t *pte = early_pte_alloc(pmd, addr, type->prot_l1);
do {
set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)), 0);
pfn++;
} while (pte++, addr += PAGE_SIZE, addr != end);
- early_pte_install(pmd, start_pte, type->prot_l1);
}
static void __init alloc_init_section(pud_t *pud, unsigned long addr,
unsigned long end, phys_addr_t phys,
- const struct mem_type *type,
- bool force_pages)
+ const struct mem_type *type)
{
pmd_t *pmd = pmd_offset(pud, addr);
@@ -660,7 +637,7 @@
* L1 entries, whereas PGDs refer to a group of L1 entries making
* up one logical pointer to an L2 table.
*/
- if (type->prot_sect && ((addr | end | phys) & ~SECTION_MASK) == 0 && !force_pages) {
+ if (type->prot_sect && ((addr | end | phys) & ~SECTION_MASK) == 0) {
pmd_t *p = pmd;
#ifndef CONFIG_ARM_LPAE
@@ -684,15 +661,14 @@
}
static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
- unsigned long end, unsigned long phys, const struct mem_type *type,
- bool force_pages)
+ unsigned long end, unsigned long phys, const struct mem_type *type)
{
pud_t *pud = pud_offset(pgd, addr);
unsigned long next;
do {
next = pud_addr_end(addr, end);
- alloc_init_section(pud, addr, next, phys, type, force_pages);
+ alloc_init_section(pud, addr, next, phys, type);
phys += next - addr;
} while (pud++, addr = next, addr != end);
}
@@ -766,7 +742,7 @@
* offsets, and we take full advantage of sections and
* supersections.
*/
-static void __init create_mapping(struct map_desc *md, bool force_pages)
+static void __init create_mapping(struct map_desc *md)
{
unsigned long addr, length, end;
phys_addr_t phys;
@@ -818,7 +794,7 @@
do {
unsigned long next = pgd_addr_end(addr, end);
- alloc_init_pud(pgd, addr, next, phys, type, force_pages);
+ alloc_init_pud(pgd, addr, next, phys, type);
phys += next - addr;
addr = next;
@@ -839,7 +815,7 @@
vm = early_alloc_aligned(sizeof(*vm) * nr, __alignof__(*vm));
for (md = io_desc; nr; md++, nr--) {
- create_mapping(md, false);
+ create_mapping(md);
vm->addr = (void *)(md->virtual & PAGE_MASK);
vm->size = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
vm->phys_addr = __pfn_to_phys(md->pfn);
@@ -1199,12 +1175,12 @@
map.virtual = 0xffff0000;
map.length = PAGE_SIZE;
map.type = MT_HIGH_VECTORS;
- create_mapping(&map, false);
+ create_mapping(&map);
if (!vectors_high()) {
map.virtual = 0;
map.type = MT_LOW_VECTORS;
- create_mapping(&map, false);
+ create_mapping(&map);
}
/*
@@ -1224,7 +1200,7 @@
map.virtual = CONFIG_ARM_USER_ACCESSIBLE_TIMER_BASE;
map.length = PAGE_SIZE;
map.type = MT_DEVICE_USER_ACCESSIBLE;
- create_mapping(&map, false);
+ create_mapping(&map);
}
}
@@ -1241,7 +1217,7 @@
static void __init kmap_init(void)
{
#ifdef CONFIG_HIGHMEM
- pkmap_page_table = early_pte_alloc_and_install(pmd_off_k(PKMAP_BASE),
+ pkmap_page_table = early_pte_alloc(pmd_off_k(PKMAP_BASE),
PKMAP_BASE, _PAGE_KERNEL_TABLE);
#endif
}
@@ -1349,14 +1325,12 @@
static void __init map_lowmem(void)
{
struct memblock_region *reg;
- phys_addr_t start;
- phys_addr_t end;
- struct map_desc map;
/* Map all the lowmem memory banks. */
for_each_memblock(memory, reg) {
- start = reg->base;
- end = start + reg->size;
+ phys_addr_t start = reg->base;
+ phys_addr_t end = start + reg->size;
+ struct map_desc map;
if (end > arm_lowmem_limit)
end = arm_lowmem_limit;
@@ -1370,28 +1344,28 @@
map.length = SECTION_SIZE;
map.type = MT_MEMORY;
- create_mapping(&map, false);
+ create_mapping(&map);
map.pfn = __phys_to_pfn(start + SECTION_SIZE);
map.virtual = __phys_to_virt(start + SECTION_SIZE);
map.length = (unsigned long)RX_AREA_END - map.virtual;
map.type = MT_MEMORY_RX;
- create_mapping(&map, false);
+ create_mapping(&map);
map.pfn = __phys_to_pfn(__pa(__start_rodata));
map.virtual = (unsigned long)__start_rodata;
map.length = __init_begin - __start_rodata;
map.type = MT_MEMORY_R;
- create_mapping(&map, false);
+ create_mapping(&map);
map.pfn = __phys_to_pfn(__pa(__init_begin));
map.virtual = (unsigned long)__init_begin;
map.length = __init_data - __init_begin;
map.type = MT_MEMORY;
- create_mapping(&map, false);
+ create_mapping(&map);
map.pfn = __phys_to_pfn(__pa(__init_data));
map.virtual = (unsigned long)__init_data;
@@ -1406,20 +1380,8 @@
map.type = MT_MEMORY;
#endif
- create_mapping(&map, false);
+ create_mapping(&map);
}
-
-#ifdef CONFIG_DEBUG_RODATA
- start = __pa(_stext) & PMD_MASK;
- end = ALIGN(__pa(__end_rodata), PMD_SIZE);
-
- map.pfn = __phys_to_pfn(start);
- map.virtual = __phys_to_virt(start);
- map.length = end - start;
- map.type = MT_MEMORY;
-
- create_mapping(&map, true);
-#endif
}
/*
diff --git a/arch/arm/mm/rodata.c b/arch/arm/mm/rodata.c
deleted file mode 100644
index 9a8eb84..0000000
--- a/arch/arm/mm/rodata.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * linux/arch/arm/mm/rodata.c
- *
- * Copyright (C) 2011 Google, Inc.
- *
- * Author: Colin Cross <ccross@android.com>
- *
- * Based on x86 implementation in arch/x86/mm/init_32.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-
-#include <asm/cache.h>
-#include <asm/pgtable.h>
-#include <asm/rodata.h>
-#include <asm/sections.h>
-#include <asm/tlbflush.h>
-
-#include "mm.h"
-
-static int kernel_set_to_readonly __read_mostly;
-
-#ifdef CONFIG_DEBUG_RODATA_TEST
-static const int rodata_test_data = 0xC3;
-
-static noinline void rodata_test(void)
-{
- int result;
-
- pr_info("%s: attempting to write to read-only section:\n", __func__);
-
- if (*(volatile int *)&rodata_test_data != 0xC3) {
- pr_err("read only data changed before test\n");
- return;
- }
-
- /*
- * Attempt to to write to rodata_test_data, trapping the expected
- * data abort. If the trap executed, result will be 1. If it didn't,
- * result will be 0xFF.
- */
- asm volatile(
- "0: str %[zero], [%[rodata_test_data]]\n"
- " mov %[result], #0xFF\n"
- " b 2f\n"
- "1: mov %[result], #1\n"
- "2:\n"
-
- /* Exception fixup - if store at label 0 faults, jumps to 1 */
- ".pushsection __ex_table, \"a\"\n"
- " .long 0b, 1b\n"
- ".popsection\n"
-
- : [result] "=r" (result)
- : [rodata_test_data] "r" (&rodata_test_data), [zero] "r" (0)
- : "memory"
- );
-
- if (result == 1)
- pr_info("write to read-only section trapped, success\n");
- else
- pr_err("write to read-only section NOT trapped, test failed\n");
-
- if (*(volatile int *)&rodata_test_data != 0xC3)
- pr_err("read only data changed during write\n");
-}
-#else
-static inline void rodata_test(void) { }
-#endif
-
-static int set_page_attributes(unsigned long virt, int numpages,
- pte_t (*f)(pte_t))
-{
- pmd_t *pmd;
- pte_t *pte;
- unsigned long start = virt;
- unsigned long end = virt + (numpages << PAGE_SHIFT);
- unsigned long pmd_end;
-
- while (virt < end) {
- pmd = pmd_off_k(virt);
- pmd_end = min(ALIGN(virt + 1, PMD_SIZE), end);
-
- if ((pmd_val(*pmd) & PMD_TYPE_MASK) != PMD_TYPE_TABLE) {
- pr_err("%s: pmd %p=%08lx for %08lx not page table\n",
- __func__, pmd, pmd_val(*pmd), virt);
- virt = pmd_end;
- continue;
- }
-
- while (virt < pmd_end) {
- pte = pte_offset_kernel(pmd, virt);
- set_pte_ext(pte, f(*pte), 0);
- virt += PAGE_SIZE;
- }
- }
-
- flush_tlb_kernel_range(start, end);
-
- return 0;
-}
-
-int set_memory_ro(unsigned long virt, int numpages)
-{
- return set_page_attributes(virt, numpages, pte_wrprotect);
-}
-EXPORT_SYMBOL(set_memory_ro);
-
-int set_memory_rw(unsigned long virt, int numpages)
-{
- return set_page_attributes(virt, numpages, pte_mkwrite);
-}
-EXPORT_SYMBOL(set_memory_rw);
-
-void set_kernel_text_rw(void)
-{
- unsigned long start = PAGE_ALIGN((unsigned long)_text);
- unsigned long size = PAGE_ALIGN((unsigned long)__end_rodata) - start;
-
- if (!kernel_set_to_readonly)
- return;
-
- pr_debug("Set kernel text: %lx - %lx to read-write\n",
- start, start + size);
-
- set_memory_rw(start, size >> PAGE_SHIFT);
-}
-
-void set_kernel_text_ro(void)
-{
- unsigned long start = PAGE_ALIGN((unsigned long)_text);
- unsigned long size = PAGE_ALIGN((unsigned long)__end_rodata) - start;
-
- if (!kernel_set_to_readonly)
- return;
-
- pr_info_once("Write protecting the kernel text section %lx - %lx\n",
- start, start + size);
-
- pr_debug("Set kernel text: %lx - %lx to read only\n",
- start, start + size);
-
- set_memory_ro(start, size >> PAGE_SHIFT);
-}
-
-void mark_rodata_ro(void)
-{
- kernel_set_to_readonly = 1;
-
- set_kernel_text_ro();
-
- rodata_test();
-}
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index ffddcba..1283fa3 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -55,6 +55,27 @@
If unsure, say Y.
+config UHID
+ tristate "User-space I/O driver support for HID subsystem"
+ depends on HID
+ default n
+ ---help---
+ Say Y here if you want to provide HID I/O Drivers from user-space.
+ This allows to write I/O drivers in user-space and feed the data from
+ the device into the kernel. The kernel parses the HID reports, loads the
+ corresponding HID Device Driver or provides input devices on top of your
+ user-space device.
+
+ This driver cannot be used to parse HID-reports in user-space and write
+ special HID-drivers. You should use hidraw for that.
+ Instead, this driver allows to write the transport-layer driver in
+ user-space like USB-HID and Bluetooth-HID do in kernel-space.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called uhid.
+
source "drivers/hid/usbhid/Kconfig"
menu "Special HID drivers"
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 22f1d16..9dca845 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -8,6 +8,7 @@
endif
obj-$(CONFIG_HID) += hid.o
+obj-$(CONFIG_UHID) += uhid.o
hid-$(CONFIG_HIDRAW) += hidraw.o
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
new file mode 100644
index 0000000..05ef4b0
--- /dev/null
+++ b/drivers/hid/uhid.c
@@ -0,0 +1,153 @@
+/*
+ * User-space I/O driver support for HID subsystem
+ * Copyright (c) 2012 David Herrmann
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/atomic.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/hid.h>
+#include <linux/input.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/uhid.h>
+#include <linux/wait.h>
+
+#define UHID_NAME "uhid"
+#define UHID_BUFSIZE 32
+
+struct uhid_device {
+ struct hid_device *hid;
+
+ wait_queue_head_t waitq;
+ spinlock_t qlock;
+ __u8 head;
+ __u8 tail;
+ struct uhid_event *outq[UHID_BUFSIZE];
+};
+
+static struct miscdevice uhid_misc;
+
+static void uhid_queue(struct uhid_device *uhid, struct uhid_event *ev)
+{
+ __u8 newhead;
+
+ newhead = (uhid->head + 1) % UHID_BUFSIZE;
+
+ if (newhead != uhid->tail) {
+ uhid->outq[uhid->head] = ev;
+ uhid->head = newhead;
+ wake_up_interruptible(&uhid->waitq);
+ } else {
+ hid_warn(uhid->hid, "Output queue is full\n");
+ kfree(ev);
+ }
+}
+
+static int uhid_queue_event(struct uhid_device *uhid, __u32 event)
+{
+ unsigned long flags;
+ struct uhid_event *ev;
+
+ ev = kzalloc(sizeof(*ev), GFP_KERNEL);
+ if (!ev)
+ return -ENOMEM;
+
+ ev->type = event;
+
+ spin_lock_irqsave(&uhid->qlock, flags);
+ uhid_queue(uhid, ev);
+ spin_unlock_irqrestore(&uhid->qlock, flags);
+
+ return 0;
+}
+
+static int uhid_char_open(struct inode *inode, struct file *file)
+{
+ struct uhid_device *uhid;
+
+ uhid = kzalloc(sizeof(*uhid), GFP_KERNEL);
+ if (!uhid)
+ return -ENOMEM;
+
+ spin_lock_init(&uhid->qlock);
+ init_waitqueue_head(&uhid->waitq);
+
+ file->private_data = uhid;
+ nonseekable_open(inode, file);
+
+ return 0;
+}
+
+static int uhid_char_release(struct inode *inode, struct file *file)
+{
+ struct uhid_device *uhid = file->private_data;
+ unsigned int i;
+
+ for (i = 0; i < UHID_BUFSIZE; ++i)
+ kfree(uhid->outq[i]);
+
+ kfree(uhid);
+
+ return 0;
+}
+
+static ssize_t uhid_char_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ return 0;
+}
+
+static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ return 0;
+}
+
+static unsigned int uhid_char_poll(struct file *file, poll_table *wait)
+{
+ return 0;
+}
+
+static const struct file_operations uhid_fops = {
+ .owner = THIS_MODULE,
+ .open = uhid_char_open,
+ .release = uhid_char_release,
+ .read = uhid_char_read,
+ .write = uhid_char_write,
+ .poll = uhid_char_poll,
+ .llseek = no_llseek,
+};
+
+static struct miscdevice uhid_misc = {
+ .fops = &uhid_fops,
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = UHID_NAME,
+};
+
+static int __init uhid_init(void)
+{
+ return misc_register(&uhid_misc);
+}
+
+static void __exit uhid_exit(void)
+{
+ misc_deregister(&uhid_misc);
+}
+
+module_init(uhid_init);
+module_exit(uhid_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
+MODULE_DESCRIPTION("User-space I/O driver support for HID subsystem");
diff --git a/drivers/net/ethernet/msm/Kconfig b/drivers/net/ethernet/msm/Kconfig
index e15f4a9..4e95614 100644
--- a/drivers/net/ethernet/msm/Kconfig
+++ b/drivers/net/ethernet/msm/Kconfig
@@ -42,6 +42,16 @@
help
Debug stats on wakeup counts.
+config MSM_RMNET_WWAN
+ tristate "MSM RMNET WWAN Network Device"
+ depends on IPA
+ default n
+ help
+ WWAN Network Driver
+ Provides an API to embedded
+ applications to send and receive
+ the data to/from A2
+
config QFEC
tristate "QFEC ethernet driver"
select MII
diff --git a/drivers/net/ethernet/msm/Makefile b/drivers/net/ethernet/msm/Makefile
index e152ec7..0afa00f 100644
--- a/drivers/net/ethernet/msm/Makefile
+++ b/drivers/net/ethernet/msm/Makefile
@@ -3,6 +3,7 @@
#
obj-$(CONFIG_MSM_RMNET) += msm_rmnet.o
+obj-$(CONFIG_MSM_RMNET_WWAN) += msm_rmnet_wwan.o
obj-$(CONFIG_MSM_RMNET_SDIO) += msm_rmnet_sdio.o
obj-$(CONFIG_MSM_RMNET_BAM) += msm_rmnet_bam.o
obj-$(CONFIG_MSM_RMNET_SMUX) += msm_rmnet_smux.o
diff --git a/drivers/net/ethernet/msm/msm_rmnet_wwan.c b/drivers/net/ethernet/msm/msm_rmnet_wwan.c
new file mode 100644
index 0000000..fe1ac46
--- /dev/null
+++ b/drivers/net/ethernet/msm/msm_rmnet_wwan.c
@@ -0,0 +1,736 @@
+/* Copyright (c) 2013, The Linux Foundation. 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.
+ */
+
+/*
+ * WWAN Network Interface.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/wakelock.h>
+#include <linux/msm_rmnet.h>
+#include <linux/if_arp.h>
+#include <linux/platform_device.h>
+#include <net/pkt_sched.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <mach/ipa.h>
+
+#define WWAN_DEV_NAME "rmnet%d"
+#define WWAN_METADATA_MASK 0x00FF0000
+#define IPA_RM_INACTIVITY_TIMER 1000
+#define WWAN_DEVICE_COUNT (8)
+#define WWAN_DATA_LEN 2000
+#define HEADROOM_FOR_A2_MUX 8 /* for mux header */
+#define TAILROOM 8 /* for padding by mux layer */
+
+enum wwan_device_status {
+ WWAN_DEVICE_INACTIVE = 0,
+ WWAN_DEVICE_ACTIVE = 1
+};
+static enum ipa_rm_resource_name
+ ipa_rm_resource_by_ch_id[WWAN_DEVICE_COUNT] = {
+ IPA_RM_RESOURCE_WWAN_0_PROD,
+ IPA_RM_RESOURCE_WWAN_1_PROD,
+ IPA_RM_RESOURCE_WWAN_2_PROD,
+ IPA_RM_RESOURCE_WWAN_3_PROD,
+ IPA_RM_RESOURCE_WWAN_4_PROD,
+ IPA_RM_RESOURCE_WWAN_5_PROD,
+ IPA_RM_RESOURCE_WWAN_6_PROD,
+ IPA_RM_RESOURCE_WWAN_7_PROD
+};
+static enum a2_mux_logical_channel_id
+ a2_mux_lcid_by_ch_id[WWAN_DEVICE_COUNT] = {
+ A2_MUX_WWAN_0,
+ A2_MUX_WWAN_1,
+ A2_MUX_WWAN_2,
+ A2_MUX_WWAN_3,
+ A2_MUX_WWAN_4,
+ A2_MUX_WWAN_5,
+ A2_MUX_WWAN_6,
+ A2_MUX_WWAN_7
+};
+
+/**
+ * struct wwan_private - WWAN private data
+ * @stats: iface statistics
+ * @ch_id: channel id
+ * @lock: spinlock for mutual exclusion
+ * @device_status: holds device status
+ *
+ * WWAN private - holds all relevant info about WWAN driver
+ */
+struct wwan_private {
+ struct net_device_stats stats;
+ uint32_t ch_id;
+ spinlock_t lock;
+ struct completion resource_granted_completion;
+ enum wwan_device_status device_status;
+};
+
+static struct net_device *netdevs[WWAN_DEVICE_COUNT];
+
+static __be16 wwan_ip_type_trans(struct sk_buff *skb)
+{
+ __be16 protocol = 0;
+ /* Determine L3 protocol */
+ switch (skb->data[0] & 0xf0) {
+ case 0x40:
+ protocol = htons(ETH_P_IP);
+ break;
+ case 0x60:
+ protocol = htons(ETH_P_IPV6);
+ break;
+ default:
+ pr_err("[%s] %s() L3 protocol decode error: 0x%02x",
+ skb->dev->name, __func__, skb->data[0] & 0xf0);
+ /* skb will be dropped in upper layer for unknown protocol */
+ break;
+ }
+ return protocol;
+}
+
+/**
+ * a2_mux_recv_notify() - Deliver an RX packet to network stack
+ *
+ * @skb: skb to be delivered
+ * @dev: network device
+ *
+ * Return codes:
+ * None
+ */
+static void a2_mux_recv_notify(void *dev, struct sk_buff *skb)
+{
+ struct wwan_private *wwan_ptr = netdev_priv(dev);
+
+ skb->dev = dev;
+ skb->protocol = wwan_ip_type_trans(skb);
+ wwan_ptr->stats.rx_packets++;
+ wwan_ptr->stats.rx_bytes += skb->len;
+ pr_debug("[%s] Rx packet #%lu len=%d\n",
+ skb->dev->name,
+ wwan_ptr->stats.rx_packets, skb->len);
+ netif_rx(skb);
+}
+
+/**
+ * wwan_send_packet() - Deliver a TX packet to A2 MUX driver.
+ *
+ * @skb: skb to be delivered
+ * @dev: network device
+ *
+ * Return codes:
+ * 0: success
+ * -EAGAIN: A2 MUX is not ready to send the skb. try later
+ * -EFAULT: A2 MUX rejected the skb
+ * -EPREM: Unknown error
+ */
+static int wwan_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ struct wwan_private *wwan_ptr = netdev_priv(dev);
+ int ret;
+
+ dev->trans_start = jiffies;
+ ret = a2_mux_write(a2_mux_lcid_by_ch_id[wwan_ptr->ch_id], skb);
+ if (ret != 0 && ret != -EAGAIN && ret != -EFAULT) {
+ pr_err("[%s] %s: write returned error %d",
+ dev->name, __func__, ret);
+ return -EPERM;
+ }
+ return ret;
+}
+
+/**
+ * a2_mux_write_done() - Update device statistics and start
+ * network stack queue is was stop and A2 MUX queue is below low
+ * watermark.
+ *
+ * @dev: network device
+ * @skb: skb to be delivered
+ *
+ * Return codes:
+ * None
+ */
+static void a2_mux_write_done(void *dev, struct sk_buff *skb)
+{
+ struct wwan_private *wwan_ptr = netdev_priv(dev);
+ unsigned long flags;
+
+ pr_debug("%s: write complete\n", __func__);
+ wwan_ptr->stats.tx_packets++;
+ wwan_ptr->stats.tx_bytes += skb->len;
+ pr_debug("[%s] Tx packet #%lu len=%d mark=0x%x\n",
+ ((struct net_device *)(dev))->name, wwan_ptr->stats.tx_packets,
+ skb->len, skb->mark);
+ dev_kfree_skb_any(skb);
+ spin_lock_irqsave(&wwan_ptr->lock, flags);
+ if (netif_queue_stopped(dev) &&
+ a2_mux_is_ch_low(a2_mux_lcid_by_ch_id[wwan_ptr->ch_id])) {
+ pr_debug("%s: Low WM hit, waking queue=%p\n",
+ __func__, skb);
+ netif_wake_queue(dev);
+ }
+ spin_unlock_irqrestore(&wwan_ptr->lock, flags);
+}
+
+/**
+ * a2_mux_notify() - Callback function for A2 MUX events Handles
+ * A2_MUX_RECEIVE and A2_MUX_WRITE_DONE events.
+ *
+ * @dev: network device
+ * @event: A2 MUX event
+ * @data: Additional data provided by A2 MUX
+ *
+ * Return codes:
+ * None
+ */
+static void a2_mux_notify(void *dev, enum a2_mux_event_type event,
+ unsigned long data)
+{
+ struct sk_buff *skb = (struct sk_buff *)data;
+
+ switch (event) {
+ case A2_MUX_RECEIVE:
+ if (!skb) {
+ pr_err("[%s] %s: No skb received",
+ ((struct net_device *)dev)->name, __func__);
+ return;
+ }
+ a2_mux_recv_notify(dev, skb);
+ break;
+ case A2_MUX_WRITE_DONE:
+ a2_mux_write_done(dev, skb);
+ break;
+ default:
+ pr_err("%s: unknown event %d\n", __func__, event);
+ break;
+ }
+}
+
+/**
+ * ipa_rm_resource_granted() - Called upon
+ * IPA_RM_RESOURCE_GRANTED event. Wakes up queue is was stopped.
+ *
+ * @work: work object supplied ny workqueue
+ *
+ * Return codes:
+ * None
+ */
+static void ipa_rm_resource_granted(void *dev)
+{
+ netif_wake_queue(dev);
+}
+/**
+ * ipa_rm_notify() - Callback function for RM events. Handles
+ * IPA_RM_RESOURCE_GRANTED and IPA_RM_RESOURCE_RELEASED events.
+ * IPA_RM_RESOURCE_GRANTED is handled in the context of shared
+ * workqueue.
+ *
+ * @dev: network device
+ * @event: IPA RM event
+ * @data: Additional data provided by IPA RM
+ *
+ * Return codes:
+ * None
+ */
+static void ipa_rm_notify(void *dev, enum ipa_rm_event event,
+ unsigned long data)
+{
+ struct wwan_private *wwan_ptr = netdev_priv(dev);
+
+ pr_debug("%s: event %d\n", __func__, event);
+ switch (event) {
+ case IPA_RM_RESOURCE_GRANTED:
+ if (wwan_ptr->device_status == WWAN_DEVICE_INACTIVE) {
+ complete_all(&wwan_ptr->resource_granted_completion);
+ break;
+ }
+ ipa_rm_resource_granted(dev);
+ break;
+ case IPA_RM_RESOURCE_RELEASED:
+ break;
+ default:
+ pr_err("%s: unknown event %d\n", __func__, event);
+ break;
+ }
+}
+
+static int wwan_register_to_ipa(struct net_device *dev)
+{
+ struct wwan_private *wwan_ptr = netdev_priv(dev);
+ struct ipa_tx_intf tx_properties = {0};
+ struct ipa_ioc_tx_intf_prop tx_ioc_properties[2] = { {0}, {0} };
+ struct ipa_ioc_tx_intf_prop *tx_ipv4_property;
+ struct ipa_ioc_tx_intf_prop *tx_ipv6_property;
+ struct ipa_rx_intf rx_properties = {0};
+ struct ipa_ioc_rx_intf_prop rx_ioc_properties[2] = { {0}, {0} };
+ struct ipa_ioc_rx_intf_prop *rx_ipv4_property;
+ struct ipa_ioc_rx_intf_prop *rx_ipv6_property;
+ int ret = 0;
+
+ pr_debug("[%s] %s:\n", dev->name, __func__);
+ tx_properties.prop = tx_ioc_properties;
+ tx_ipv4_property = &tx_properties.prop[0];
+ tx_ipv4_property->ip = IPA_IP_v4;
+ tx_ipv4_property->dst_pipe = IPA_CLIENT_A2_EMBEDDED_CONS;
+ snprintf(tx_ipv4_property->hdr_name, IPA_RESOURCE_NAME_MAX, "%s%d",
+ A2_MUX_HDR_NAME_V4_PREF,
+ a2_mux_lcid_by_ch_id[wwan_ptr->ch_id]);
+ tx_ipv6_property = &tx_properties.prop[1];
+ tx_ipv6_property->ip = IPA_IP_v6;
+ tx_ipv6_property->dst_pipe = IPA_CLIENT_A2_EMBEDDED_CONS;
+ snprintf(tx_ipv6_property->hdr_name, IPA_RESOURCE_NAME_MAX, "%s%d",
+ A2_MUX_HDR_NAME_V6_PREF,
+ a2_mux_lcid_by_ch_id[wwan_ptr->ch_id]);
+ tx_properties.num_props = 2;
+ rx_properties.prop = rx_ioc_properties;
+ rx_ipv4_property = &rx_properties.prop[0];
+ rx_ipv4_property->ip = IPA_IP_v4;
+ rx_ipv4_property->attrib.attrib_mask |= IPA_FLT_META_DATA;
+ rx_ipv4_property->attrib.meta_data = wwan_ptr->ch_id;
+ rx_ipv4_property->attrib.meta_data_mask = WWAN_METADATA_MASK;
+ rx_ipv4_property->src_pipe = IPA_CLIENT_A2_EMBEDDED_PROD;
+ rx_ipv6_property = &rx_properties.prop[1];
+ rx_ipv6_property->ip = IPA_IP_v6;
+ rx_ipv6_property->attrib.attrib_mask |= IPA_FLT_META_DATA;
+ rx_ipv6_property->attrib.meta_data = wwan_ptr->ch_id;
+ rx_ipv6_property->attrib.meta_data_mask = WWAN_METADATA_MASK;
+ rx_ipv6_property->src_pipe = IPA_CLIENT_A2_EMBEDDED_PROD;
+ rx_properties.num_props = 2;
+ ret = ipa_register_intf(dev->name, &tx_properties, &rx_properties);
+ if (ret) {
+ pr_err("[%s] %s: ipa_register_intf failed %d\n", dev->name,
+ __func__, ret);
+ return ret;
+ }
+ return 0;
+}
+
+static int __wwan_open(struct net_device *dev)
+{
+ int r;
+ struct wwan_private *wwan_ptr = netdev_priv(dev);
+
+ pr_debug("[%s] __wwan_open()\n", dev->name);
+ if (wwan_ptr->device_status != WWAN_DEVICE_ACTIVE) {
+ INIT_COMPLETION(wwan_ptr->resource_granted_completion);
+ r = ipa_rm_inactivity_timer_request_resource(
+ ipa_rm_resource_by_ch_id[wwan_ptr->ch_id]);
+ if (r < 0 && r != -EINPROGRESS) {
+ pr_err("%s: ipa rm timer request resource failed %d\n",
+ __func__, r);
+ return -ENODEV;
+ }
+ if (r == -EINPROGRESS) {
+ wait_for_completion(
+ &wwan_ptr->resource_granted_completion);
+ }
+ r = a2_mux_open_channel(a2_mux_lcid_by_ch_id[wwan_ptr->ch_id],
+ dev, a2_mux_notify);
+ if (r < 0) {
+ pr_err("%s: ch=%d failed with rc %d\n",
+ __func__, wwan_ptr->ch_id, r);
+ ipa_rm_inactivity_timer_release_resource(
+ ipa_rm_resource_by_ch_id[wwan_ptr->ch_id]);
+ return -ENODEV;
+ }
+ ipa_rm_inactivity_timer_release_resource(
+ ipa_rm_resource_by_ch_id[wwan_ptr->ch_id]);
+ r = wwan_register_to_ipa(dev);
+ if (r < 0) {
+ pr_err("%s: ch=%d failed to register to IPA rc %d\n",
+ __func__, wwan_ptr->ch_id, r);
+ return -ENODEV;
+ }
+ }
+ wwan_ptr->device_status = WWAN_DEVICE_ACTIVE;
+ return 0;
+}
+
+/**
+ * wwan_open() - Opens the wwan network interface. Opens logical
+ * channel on A2 MUX driver and starts the network stack queue
+ *
+ * @dev: network device
+ *
+ * Return codes:
+ * 0: success
+ * -ENODEV: Error while opening logical channel on A2 MUX driver
+ */
+static int wwan_open(struct net_device *dev)
+{
+ int rc = 0;
+
+ pr_debug("[%s] wwan_open()\n", dev->name);
+ rc = __wwan_open(dev);
+ if (rc == 0)
+ netif_start_queue(dev);
+ return rc;
+}
+
+
+static int __wwan_close(struct net_device *dev)
+{
+ struct wwan_private *wwan_ptr = netdev_priv(dev);
+ int rc = 0;
+
+ if (wwan_ptr->device_status == WWAN_DEVICE_ACTIVE) {
+ wwan_ptr->device_status = WWAN_DEVICE_INACTIVE;
+ /* do not close wwan port once up, this causes
+ remote side to hang if tried to open again */
+ INIT_COMPLETION(wwan_ptr->resource_granted_completion);
+ rc = ipa_rm_inactivity_timer_request_resource(
+ ipa_rm_resource_by_ch_id[wwan_ptr->ch_id]);
+ if (rc < 0 && rc != -EINPROGRESS) {
+ pr_err("%s: ipa rm timer request resource failed %d\n",
+ __func__, rc);
+ return -ENODEV;
+ }
+ if (rc == -EINPROGRESS) {
+ wait_for_completion(
+ &wwan_ptr->resource_granted_completion);
+ }
+ rc = a2_mux_close_channel(
+ a2_mux_lcid_by_ch_id[wwan_ptr->ch_id]);
+ if (rc) {
+ pr_err("[%s] %s: a2_mux_close_channel failed %d\n",
+ dev->name, __func__, rc);
+ ipa_rm_inactivity_timer_release_resource(
+ ipa_rm_resource_by_ch_id[wwan_ptr->ch_id]);
+ return rc;
+ }
+ ipa_rm_inactivity_timer_release_resource(
+ ipa_rm_resource_by_ch_id[wwan_ptr->ch_id]);
+ rc = ipa_deregister_intf(dev->name);
+ if (rc) {
+ pr_err("[%s] %s: ipa_deregister_intf failed %d\n",
+ dev->name, __func__, rc);
+ return rc;
+ }
+ return rc;
+ } else
+ return -EBADF;
+}
+
+/**
+ * wwan_stop() - Stops the wwan network interface. Closes
+ * logical channel on A2 MUX driver and stops the network stack
+ * queue
+ *
+ * @dev: network device
+ *
+ * Return codes:
+ * 0: success
+ * -ENODEV: Error while opening logical channel on A2 MUX driver
+ */
+static int wwan_stop(struct net_device *dev)
+{
+ pr_debug("[%s] wwan_stop()\n", dev->name);
+ __wwan_close(dev);
+ netif_stop_queue(dev);
+ return 0;
+}
+
+static int wwan_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if (0 > new_mtu || WWAN_DATA_LEN < new_mtu)
+ return -EINVAL;
+ pr_debug("[%s] MTU change: old=%d new=%d\n",
+ dev->name, dev->mtu, new_mtu);
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+/**
+ * wwan_xmit() - Transmits an skb. In charge of asking IPA
+ * RM needed resources. In case that IPA RM is not ready, then
+ * the skb is saved for tranmitting as soon as IPA RM resources
+ * are granted.
+ *
+ * @skb: skb to be transmitted
+ * @dev: network device
+ *
+ * Return codes:
+ * 0: success
+ * NETDEV_TX_BUSY: Error while transmitting the skb. Try again
+ * later
+ * -EFAULT: Error while transmitting the skb
+ */
+static int wwan_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct wwan_private *wwan_ptr = netdev_priv(dev);
+ unsigned long flags;
+ int ret = 0;
+
+ if (netif_queue_stopped(dev)) {
+ pr_err("[%s]fatal: wwan_xmit called when netif_queue stopped\n",
+ dev->name);
+ return 0;
+ }
+ ret = ipa_rm_inactivity_timer_request_resource(
+ ipa_rm_resource_by_ch_id[wwan_ptr->ch_id]);
+ if (ret == -EINPROGRESS) {
+ netif_stop_queue(dev);
+ return NETDEV_TX_BUSY;
+ }
+ if (ret) {
+ pr_err("[%s] fatal: ipa rm timer request resource failed %d\n",
+ dev->name, ret);
+ return -EFAULT;
+ }
+ ret = wwan_send_packet(skb, dev);
+ if (ret == -EPERM) {
+ ret = NETDEV_TX_BUSY;
+ goto exit;
+ }
+ /*
+ * detected SSR a bit early. shut some things down now, and leave
+ * the rest to the main ssr handling code when that happens later
+ */
+ if (ret == -EFAULT) {
+ netif_carrier_off(dev);
+ dev_kfree_skb_any(skb);
+ ret = 0;
+ goto exit;
+ }
+ if (ret == -EAGAIN) {
+ /*
+ * This should not happen
+ * EAGAIN means we attempted to overflow the high watermark
+ * Clearly the queue is not stopped like it should be, so
+ * stop it and return BUSY to the TCP/IP framework. It will
+ * retry this packet with the queue is restarted which happens
+ * in the write_done callback when the low watermark is hit.
+ */
+ netif_stop_queue(dev);
+ ret = NETDEV_TX_BUSY;
+ goto exit;
+ }
+ spin_lock_irqsave(&wwan_ptr->lock, flags);
+ if (a2_mux_is_ch_full(a2_mux_lcid_by_ch_id[wwan_ptr->ch_id])) {
+ netif_stop_queue(dev);
+ pr_debug("%s: High WM hit, stopping queue=%p\n",
+ __func__, skb);
+ }
+ spin_unlock_irqrestore(&wwan_ptr->lock, flags);
+exit:
+ ipa_rm_inactivity_timer_release_resource(
+ ipa_rm_resource_by_ch_id[wwan_ptr->ch_id]);
+ return ret;
+}
+
+static struct net_device_stats *wwan_get_stats(struct net_device *dev)
+{
+ struct wwan_private *wwan_ptr = netdev_priv(dev);
+ return &wwan_ptr->stats;
+}
+
+static void wwan_tx_timeout(struct net_device *dev)
+{
+ pr_warning("[%s] wwan_tx_timeout()\n", dev->name);
+}
+
+/**
+ * wwan_ioctl() - I/O control for wwan network driver.
+ *
+ * @dev: network device
+ * @ifr: ignored
+ * @cmd: cmd to be excecuded. can be one of the following:
+ * WWAN_IOCTL_OPEN - Open the network interface
+ * WWAN_IOCTL_CLOSE - Close the network interface
+ *
+ * Return codes:
+ * 0: success
+ * NETDEV_TX_BUSY: Error while transmitting the skb. Try again
+ * later
+ * -EFAULT: Error while transmitting the skb
+ */
+static int wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ int rc = 0;
+
+ switch (cmd) {
+ case RMNET_IOCTL_SET_LLP_IP: /* Set RAWIP protocol */
+ break;
+ case RMNET_IOCTL_GET_LLP: /* Get link protocol state */
+ ifr->ifr_ifru.ifru_data = (void *) RMNET_MODE_LLP_IP;
+ break;
+ case RMNET_IOCTL_SET_QOS_DISABLE: /* Set QoS header disabled */
+ break;
+ case RMNET_IOCTL_FLOW_ENABLE:
+ tc_qdisc_flow_control(dev, (u32)ifr->ifr_data, 1);
+ pr_debug("[%s] %s: enabled flow", dev->name, __func__);
+ break;
+ case RMNET_IOCTL_FLOW_DISABLE:
+ tc_qdisc_flow_control(dev, (u32)ifr->ifr_data, 0);
+ pr_debug("[%s] %s: disabled flow", dev->name, __func__);
+ break;
+ case RMNET_IOCTL_GET_QOS: /* Get QoS header state */
+ /* QoS disabled */
+ ifr->ifr_ifru.ifru_data = (void *) 0;
+ break;
+ case RMNET_IOCTL_GET_OPMODE: /* Get operation mode */
+ ifr->ifr_ifru.ifru_data = (void *) RMNET_MODE_LLP_IP;
+ break;
+ case RMNET_IOCTL_OPEN: /* Open transport port */
+ rc = __wwan_open(dev);
+ pr_debug("[%s] wwan_ioctl(): open transport port\n",
+ dev->name);
+ break;
+ case RMNET_IOCTL_CLOSE: /* Close transport port */
+ rc = __wwan_close(dev);
+ pr_debug("[%s] wwan_ioctl(): close transport port\n",
+ dev->name);
+ break;
+ default:
+ pr_err("[%s] error: wwan_ioct called for unsupported cmd[%d]",
+ dev->name, cmd);
+ return -EINVAL;
+ }
+ return rc;
+}
+
+static const struct net_device_ops wwan_ops_ip = {
+ .ndo_open = wwan_open,
+ .ndo_stop = wwan_stop,
+ .ndo_start_xmit = wwan_xmit,
+ .ndo_get_stats = wwan_get_stats,
+ .ndo_tx_timeout = wwan_tx_timeout,
+ .ndo_do_ioctl = wwan_ioctl,
+ .ndo_change_mtu = wwan_change_mtu,
+ .ndo_set_mac_address = 0,
+ .ndo_validate_addr = 0,
+};
+
+/**
+ * wwan_setup() - Setups the wwan network driver.
+ *
+ * @dev: network device
+ *
+ * Return codes:
+ * None
+ */
+static void wwan_setup(struct net_device *dev)
+{
+ dev->netdev_ops = &wwan_ops_ip;
+ ether_setup(dev);
+ /* set this after calling ether_setup */
+ dev->header_ops = 0; /* No header */
+ dev->type = ARPHRD_RAWIP;
+ dev->hard_header_len = 0;
+ dev->mtu = WWAN_DATA_LEN;
+ dev->addr_len = 0;
+ dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST);
+ dev->needed_headroom = HEADROOM_FOR_A2_MUX;
+ dev->needed_tailroom = TAILROOM;
+ dev->watchdog_timeo = 1000;
+}
+
+/**
+ * wwan_init() - Initialized the module and registers as a
+ * network interface to the network stack
+ *
+ * Return codes:
+ * 0: success
+ * -ENOMEM: No memory available
+ * -EFAULT: Internal error
+ */
+static int __init wwan_init(void)
+{
+ int ret;
+ struct net_device *dev;
+ struct wwan_private *wwan_ptr;
+ unsigned n;
+ struct ipa_rm_create_params ipa_rm_params;
+
+ pr_info("%s: WWAN devices[%d]\n", __func__, WWAN_DEVICE_COUNT);
+ for (n = 0; n < WWAN_DEVICE_COUNT; n++) {
+ dev = alloc_netdev(sizeof(struct wwan_private),
+ WWAN_DEV_NAME, wwan_setup);
+ if (!dev) {
+ pr_err("%s: no memory for netdev %d\n", __func__, n);
+ ret = -ENOMEM;
+ goto fail;
+ }
+ netdevs[n] = dev;
+ wwan_ptr = netdev_priv(dev);
+ wwan_ptr->ch_id = n;
+ spin_lock_init(&wwan_ptr->lock);
+ init_completion(&wwan_ptr->resource_granted_completion);
+ memset(&ipa_rm_params, 0, sizeof(struct ipa_rm_create_params));
+ ipa_rm_params.name = ipa_rm_resource_by_ch_id[n];
+ ipa_rm_params.reg_params.user_data = dev;
+ ipa_rm_params.reg_params.notify_cb = ipa_rm_notify;
+ ret = ipa_rm_create_resource(&ipa_rm_params);
+ if (ret) {
+ pr_err("%s: unable to create resourse %d in IPA RM\n",
+ __func__, ipa_rm_resource_by_ch_id[n]);
+ goto fail;
+ }
+ ret = ipa_rm_inactivity_timer_init(ipa_rm_resource_by_ch_id[n],
+ IPA_RM_INACTIVITY_TIMER);
+ if (ret) {
+ pr_err("%s: ipa rm timer init failed %d on ins %d\n",
+ __func__, ret, n);
+ goto fail;
+ }
+ ret = ipa_rm_add_dependency(ipa_rm_resource_by_ch_id[n],
+ IPA_RM_RESOURCE_A2_CONS);
+ if (ret) {
+ pr_err("%s: unable to add dependency %d rc=%d\n",
+ __func__, n, ret);
+ goto fail;
+ }
+ ret = register_netdev(dev);
+ if (ret) {
+ pr_err("%s: unable to register netdev %d rc=%d\n",
+ __func__, n, ret);
+ goto fail;
+ }
+ }
+ return 0;
+fail:
+ for (n = 0; n < WWAN_DEVICE_COUNT; n++) {
+ if (!netdevs[n])
+ break;
+ unregister_netdev(netdevs[n]);
+ ipa_rm_inactivity_timer_destroy(ipa_rm_resource_by_ch_id[n]);
+ free_netdev(netdevs[n]);
+ netdevs[n] = NULL;
+ }
+ return ret;
+}
+late_initcall(wwan_init);
+
+void wwan_cleanup(void)
+{
+ unsigned n;
+
+ pr_info("%s: WWAN devices[%d]\n", __func__, WWAN_DEVICE_COUNT);
+ for (n = 0; n < WWAN_DEVICE_COUNT; n++) {
+ unregister_netdev(netdevs[n]);
+ ipa_rm_inactivity_timer_destroy(ipa_rm_resource_by_ch_id[n]);
+ free_netdev(netdevs[n]);
+ netdevs[n] = NULL;
+ }
+}
+
+MODULE_DESCRIPTION("WWAN Network Interface");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/msm/ipa/a2_service.c b/drivers/platform/msm/ipa/a2_service.c
index 2c5245c..60cb6bd 100644
--- a/drivers/platform/msm/ipa/a2_service.c
+++ b/drivers/platform/msm/ipa/a2_service.c
@@ -53,6 +53,8 @@
spinlock_t lock;
int num_tx_pkts;
int use_wm;
+ u32 v4_hdr_hdl;
+ u32 v6_hdr_hdl;
};
struct tx_pkt_info {
struct sk_buff *skb;
@@ -70,6 +72,7 @@
u8 ch_id;
u16 pkt_len;
};
+
struct a2_mux_context_type {
u32 tethered_prod;
u32 tethered_cons;
@@ -515,6 +518,9 @@
goto bridge_tethered_dl_failed;
}
memset(&connect_params, 0, sizeof(struct ipa_sys_connect_params));
+ connect_params.ipa_ep_cfg.hdr.hdr_len = sizeof(struct bam_mux_hdr);
+ connect_params.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
+ connect_params.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 6;
connect_params.client = IPA_CLIENT_A2_EMBEDDED_CONS;
connect_params.notify = ipa_embedded_notify;
connect_params.desc_fifo_sz = 0x800;
@@ -527,6 +533,9 @@
goto bridge_embedded_ul_failed;
}
memset(&connect_params, 0, sizeof(struct ipa_sys_connect_params));
+ connect_params.ipa_ep_cfg.hdr.hdr_len = sizeof(struct bam_mux_hdr);
+ connect_params.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
+ connect_params.ipa_ep_cfg.hdr.hdr_ofst_metadata = 4;
connect_params.client = IPA_CLIENT_A2_EMBEDDED_PROD;
connect_params.notify = ipa_embedded_notify;
connect_params.desc_fifo_sz = 0x800;
@@ -1006,6 +1015,176 @@
}
/**
+ * a2_mux_add_hdr() - called when MUX header should
+ * be added
+ * @lcid: logical channel ID
+ *
+ * Returns: 0 on success, negative on failure
+ */
+static int a2_mux_add_hdr(enum a2_mux_logical_channel_id lcid)
+{
+ struct ipa_ioc_add_hdr *hdrs;
+ struct ipa_hdr_add *ipv4_hdr;
+ struct ipa_hdr_add *ipv6_hdr;
+ struct bam_mux_hdr *dmux_hdr;
+ int rc;
+
+ IPADBG("%s: ch %d\n", __func__, lcid);
+
+ if (lcid < A2_MUX_WWAN_0 || lcid > A2_MUX_WWAN_7) {
+ IPAERR("%s: non valid lcid passed: %d\n", __func__, lcid);
+ return -EINVAL;
+ }
+
+
+ hdrs = kzalloc(sizeof(struct ipa_ioc_add_hdr) +
+ 2 * sizeof(struct ipa_hdr_add), GFP_KERNEL);
+ if (!hdrs) {
+ IPAERR("%s: hdr allocation fail for ch %d\n", __func__, lcid);
+ return -ENOMEM;
+ }
+
+ ipv4_hdr = &hdrs->hdr[0];
+ ipv6_hdr = &hdrs->hdr[1];
+
+ dmux_hdr = (struct bam_mux_hdr *)ipv4_hdr->hdr;
+ snprintf(ipv4_hdr->name, IPA_RESOURCE_NAME_MAX, "%s%d",
+ A2_MUX_HDR_NAME_V4_PREF, lcid);
+ dmux_hdr->magic_num = BAM_MUX_HDR_MAGIC_NO;
+ dmux_hdr->cmd = BAM_MUX_HDR_CMD_DATA;
+ dmux_hdr->reserved = 0;
+ dmux_hdr->ch_id = lcid;
+
+ /* Packet lenght is added by IPA */
+ dmux_hdr->pkt_len = 0;
+ dmux_hdr->pad_len = 0;
+
+ dmux_hdr->magic_num = htons(dmux_hdr->magic_num);
+ IPADBG("converted to network order magic_num=%d\n",
+ dmux_hdr->magic_num);
+
+ ipv4_hdr->hdr_len = sizeof(struct bam_mux_hdr);
+ ipv4_hdr->is_partial = 0;
+
+ dmux_hdr = (struct bam_mux_hdr *)ipv6_hdr->hdr;
+ snprintf(ipv6_hdr->name, IPA_RESOURCE_NAME_MAX, "%s%d",
+ A2_MUX_HDR_NAME_V6_PREF, lcid);
+ dmux_hdr->magic_num = BAM_MUX_HDR_MAGIC_NO;
+ dmux_hdr->cmd = BAM_MUX_HDR_CMD_DATA;
+ dmux_hdr->reserved = 0;
+ dmux_hdr->ch_id = lcid;
+
+ /* Packet lenght is added by IPA */
+ dmux_hdr->pkt_len = 0;
+ dmux_hdr->pad_len = 0;
+
+ dmux_hdr->magic_num = htons(dmux_hdr->magic_num);
+ IPADBG("converted to network order magic_num=%d\n",
+ dmux_hdr->magic_num);
+
+ ipv6_hdr->hdr_len = sizeof(struct bam_mux_hdr);
+ ipv6_hdr->is_partial = 0;
+
+ hdrs->commit = 1;
+ hdrs->num_hdrs = 2;
+
+ rc = ipa_add_hdr(hdrs);
+ if (rc) {
+ IPAERR("Fail on Header-Insertion(%d)\n", rc);
+ goto bail;
+ }
+
+ if (ipv4_hdr->status) {
+ IPAERR("Fail on Header-Insertion ipv4(%d)\n",
+ ipv4_hdr->status);
+ rc = ipv4_hdr->status;
+ goto bail;
+ }
+
+ if (ipv6_hdr->status) {
+ IPAERR("%s: Fail on Header-Insertion ipv4(%d)\n", __func__,
+ ipv6_hdr->status);
+ rc = ipv6_hdr->status;
+ goto bail;
+ }
+
+ a2_mux_ctx->bam_ch[lcid].v4_hdr_hdl = ipv4_hdr->hdr_hdl;
+ a2_mux_ctx->bam_ch[lcid].v6_hdr_hdl = ipv6_hdr->hdr_hdl;
+
+ rc = 0;
+bail:
+ kfree(hdrs);
+ return rc;
+}
+
+/**
+ * a2_mux_del_hdr() - called when MUX header should
+ * be removed
+ * @lcid: logical channel ID
+ *
+ * Returns: 0 on success, negative on failure
+ */
+static int a2_mux_del_hdr(enum a2_mux_logical_channel_id lcid)
+{
+ struct ipa_ioc_del_hdr *hdrs;
+ struct ipa_hdr_del *ipv4_hdl;
+ struct ipa_hdr_del *ipv6_hdl;
+ int rc;
+
+ IPADBG("%s: ch %d\n", __func__, lcid);
+
+ if (lcid < A2_MUX_WWAN_0 || lcid > A2_MUX_WWAN_7) {
+ IPAERR("invalid lcid passed: %d\n", lcid);
+ return -EINVAL;
+ }
+
+
+ hdrs = kzalloc(sizeof(struct ipa_ioc_del_hdr) +
+ 2 * sizeof(struct ipa_hdr_del), GFP_KERNEL);
+ if (!hdrs) {
+ IPAERR("hdr alloc fail for ch %d\n", lcid);
+ return -ENOMEM;
+ }
+
+ ipv4_hdl = &hdrs->hdl[0];
+ ipv6_hdl = &hdrs->hdl[1];
+
+ ipv4_hdl->hdl = a2_mux_ctx->bam_ch[lcid].v4_hdr_hdl;
+ ipv6_hdl->hdl = a2_mux_ctx->bam_ch[lcid].v6_hdr_hdl;
+
+ hdrs->commit = 1;
+ hdrs->num_hdls = 2;
+
+ rc = ipa_del_hdr(hdrs);
+ if (rc) {
+ IPAERR("Fail on Del Header-Insertion(%d)\n", rc);
+ goto bail;
+ }
+
+ if (ipv4_hdl->status) {
+ IPAERR("Fail on Del Header-Insertion ipv4(%d)\n",
+ ipv4_hdl->status);
+ rc = ipv4_hdl->status;
+ goto bail;
+ }
+ a2_mux_ctx->bam_ch[lcid].v4_hdr_hdl = 0;
+
+ if (ipv6_hdl->status) {
+ IPAERR("Fail on Del Header-Insertion ipv4(%d)\n",
+ ipv6_hdl->status);
+ rc = ipv6_hdl->status;
+ goto bail;
+ }
+ a2_mux_ctx->bam_ch[lcid].v6_hdr_hdl = 0;
+
+ rc = 0;
+bail:
+ kfree(hdrs);
+ return rc;
+
+}
+
+/**
* a2_mux_open_channel() - opens logical channel
* to A2
* @lcid: logical channel ID
@@ -1090,6 +1269,12 @@
kfree(hdr);
return rc;
}
+ rc = a2_mux_add_hdr(lcid);
+ if (rc) {
+ IPAERR("a2_mux_add_hdr failed %d; ch: %d\n",
+ rc, lcid);
+ return rc;
+ }
}
open_done:
@@ -1154,6 +1339,13 @@
kfree(hdr);
return rc;
}
+
+ rc = a2_mux_del_hdr(lcid);
+ if (rc) {
+ IPAERR("a2_mux_del_hdr failed %d; ch: %d\n",
+ rc, lcid);
+ return rc;
+ }
}
IPADBG("%s: closed ch %d\n", __func__, lcid);
return 0;
diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h
index 14195d7..dae302c 100644
--- a/drivers/platform/msm/ipa/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_i.h
@@ -823,4 +823,7 @@
int a2_mux_init(void);
int a2_mux_exit(void);
+void wwan_cleanup(void);
+
+
#endif /* _IPA_I_H_ */
diff --git a/drivers/platform/msm/ssbi.c b/drivers/platform/msm/ssbi.c
index a08eb48..e0bbdd1 100644
--- a/drivers/platform/msm/ssbi.c
+++ b/drivers/platform/msm/ssbi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
* Copyright (c) 2010, Google Inc.
*
* Original authors: Code Aurora Forum
@@ -362,7 +362,7 @@
ssbi->base = ioremap(mem_res->start, resource_size(mem_res));
if (!ssbi->base) {
- pr_err("ioremap of 0x%p failed\n", (void *)mem_res->start);
+ pr_err("ioremap failed: %pr\n", mem_res);
ret = -EINVAL;
goto err_ioremap;
}
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index f87a443..03b3e0d 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -255,12 +255,9 @@
struct dentry *dent;
struct bms_notify bms_notify;
int *usb_trim_table;
- struct regulator *vreg_xoadc;
bool ext_charging;
bool ext_charge_done;
bool iusb_fine_res;
- bool final_kickstart;
- bool lockup_lpm_wrkarnd;
DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
struct work_struct battery_id_valid_work;
int64_t batt_id_min;
@@ -296,6 +293,7 @@
int stop_chg_upon_expiry;
bool disable_aicl;
int usb_type;
+ bool disable_chg_rmvl_wrkarnd;
};
/* user space parameter to limit usb current */
@@ -311,7 +309,6 @@
static struct pm8921_chg_chip *the_chip;
-static DEFINE_SPINLOCK(lpm_lock);
#define LPM_ENABLE_BIT BIT(2)
static int pm8921_chg_set_lpm(struct pm8921_chg_chip *chip, int enable)
{
@@ -340,66 +337,11 @@
static int pm_chg_write(struct pm8921_chg_chip *chip, u16 addr, u8 reg)
{
int rc;
- unsigned long flags = 0;
- u8 temp;
- /* Disable LPM */
- if (chip->lockup_lpm_wrkarnd) {
- spin_lock_irqsave(&lpm_lock, flags);
+ rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
+ if (rc)
+ pr_err("failed: addr=%03X, rc=%d\n", addr, rc);
- /*
- * This delay is to prevent exit out of 32khz mode within
- * 200uS. It could be that chg was removed just few uS before
- * this gets called.
- */
- udelay(200);
- /* no clks */
- temp = 0xD1;
- rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
- if (rc) {
- pr_err("Error %d writing %d to CHG_TEST\n", rc, temp);
- goto release_lpm_lock;
- }
-
- /* force 19.2Mhz before reading */
- temp = 0xD3;
- rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
- if (rc) {
- pr_err("Error %d writing %d to CHG_TEST\n", rc, temp);
- goto release_lpm_lock;
- }
-
- rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
- if (rc) {
- pr_err("failed: addr=%03X, rc=%d\n", addr, rc);
- goto release_lpm_lock;
- }
-
- /* no clks */
- temp = 0xD1;
- rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
- if (rc) {
- pr_err("Error %d writing %d to CHG_TEST\n", rc, temp);
- goto release_lpm_lock;
- }
-
- /* switch to hw clk selection */
- temp = 0xD0;
- rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
- if (rc) {
- pr_err("Error %d writing %d to CHG_TEST\n", rc, temp);
- goto release_lpm_lock;
- }
-
- udelay(200);
-
-release_lpm_lock:
- spin_unlock_irqrestore(&lpm_lock, flags);
- } else {
- rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
- if (rc)
- pr_err("failed: addr=%03X, rc=%d\n", addr, rc);
- }
return rc;
}
@@ -430,23 +372,6 @@
chip->pmic_chg_irq[irq_id]);
}
-static int is_chg_on_bat(struct pm8921_chg_chip *chip)
-{
- return !(pm_chg_get_rt_status(chip, DCIN_VALID_IRQ)
- || pm_chg_get_rt_status(chip, USBIN_VALID_IRQ));
-}
-
-static void pm8921_chg_bypass_bat_gone_debounce(struct pm8921_chg_chip *chip,
- int bypass)
-{
- int rc;
-
- rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, bypass ? 0x89 : 0x88);
- if (rc) {
- pr_err("Failed to set bypass bit to %d rc=%d\n", bypass, rc);
- }
-}
-
/* Treat OverVoltage/UnderVoltage as source missing */
static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
{
@@ -469,35 +394,8 @@
static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
{
u8 temp;
- unsigned long flags = 0;
int err = 0, ret = 0;
- if (chip->lockup_lpm_wrkarnd) {
- spin_lock_irqsave(&lpm_lock, flags);
-
- /*
- * This delay is to prevent exit out of 32khz mode within
- * 200uS. It could be that chg was removed just few uS before
- * this gets called.
- */
- udelay(200);
- /* no clks */
- temp = 0xD1;
- err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
- goto err_out;
- }
-
- /* force 19.2Mhz before reading */
- temp = 0xD3;
- err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
- goto err_out;
- }
- }
-
temp = CAPTURE_FSM_STATE_CMD;
err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
if (err) {
@@ -535,29 +433,7 @@
/* get the upper 1 bit */
ret |= (temp & 0x1) << 4;
- if (chip->lockup_lpm_wrkarnd) {
- /* no clks */
- temp = 0xD1;
- err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
- goto err_out;
- }
-
- /* switch to hw clk selection */
- temp = 0xD0;
- err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
- goto err_out;
- }
-
- udelay(200);
- }
-
err_out:
- if (chip->lockup_lpm_wrkarnd)
- spin_unlock_irqrestore(&lpm_lock, flags);
if (err)
return err;
@@ -568,35 +444,8 @@
static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
{
u8 temp, data;
- unsigned long flags = 0;
int err = 0;
- if (chip->lockup_lpm_wrkarnd) {
- spin_lock_irqsave(&lpm_lock, flags);
-
- /*
- * This delay is to prevent exit out of 32khz mode within
- * 200uS. It could be that chg was removed just few uS before
- * this gets called.
- */
- udelay(200);
- /* no clks */
- temp = 0xD1;
- err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
- goto err_out;
- }
-
- /* force 19.2Mhz before reading */
- temp = 0xD3;
- err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
- goto err_out;
- }
- }
-
temp = READ_BANK_6;
err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
if (err) {
@@ -610,29 +459,7 @@
goto err_out;
}
- if (chip->lockup_lpm_wrkarnd) {
- /* no clks */
- temp = 0xD1;
- err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
- goto err_out;
- }
-
- /* switch to hw clk selection */
- temp = 0xD0;
- err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
- goto err_out;
- }
-
- udelay(200);
- }
-
err_out:
- if (chip->lockup_lpm_wrkarnd)
- spin_unlock_irqrestore(&lpm_lock, flags);
if (err)
return err;
@@ -2099,10 +1926,10 @@
* This would also apply when the battery has been
* removed from the running system.
*/
- if (the_chip && !get_prop_batt_present(the_chip)
+ if (mA == 0 && the_chip && !get_prop_batt_present(the_chip)
&& !is_dc_chg_plugged_in(the_chip)) {
if (!the_chip->has_dc_supply) {
- pr_err("rejected: no other power source connected\n");
+ pr_err("rejected: no other power source mA = %d\n", mA);
return;
}
}
@@ -2377,96 +2204,9 @@
return get_prop_batt_temp(the_chip);
}
-static int __pm8921_apply_19p2mhz_kickstart(struct pm8921_chg_chip *chip)
-{
- int err;
- u8 temp;
-
-
- temp = 0xD1;
- err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
- return err;
- }
-
- temp = 0xD3;
- err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
- return err;
- }
-
- temp = 0xD1;
- err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
- return err;
- }
-
- temp = 0xD5;
- err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
- return err;
- }
-
- /* Wait a few clock cycles before re-enabling hw clock switching */
- udelay(183);
-
- temp = 0xD1;
- err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
- return err;
- }
-
- temp = 0xD0;
- err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
- if (err) {
- pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
- return err;
- }
-
- /* Wait for few clock cycles before re-enabling LPM */
- udelay(32);
-
- return 0;
-}
-
-static int pm8921_apply_19p2mhz_kickstart(struct pm8921_chg_chip *chip)
-{
- int err;
- unsigned long flags = 0;
-
- spin_lock_irqsave(&lpm_lock, flags);
- err = pm8921_chg_set_lpm(chip, 0);
- if (err) {
- pr_err("Error settig LPM rc=%d\n", err);
- goto kick_err;
- }
-
- __pm8921_apply_19p2mhz_kickstart(chip);
-
-kick_err:
- err = pm8921_chg_set_lpm(chip, 1);
- if (err)
- pr_err("Error settig LPM rc=%d\n", err);
-
- spin_unlock_irqrestore(&lpm_lock, flags);
-
- return err;
-}
-
static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
{
- int usb_present, rc = 0;
-
- if (chip->lockup_lpm_wrkarnd) {
- rc = pm8921_apply_19p2mhz_kickstart(chip);
- if (rc)
- pr_err("Failed to apply kickstart rc=%d\n", rc);
- }
+ int usb_present;
pm_chg_failed_clear(chip, 1);
usb_present = is_usb_chg_plugged_in(chip);
@@ -2476,11 +2216,6 @@
power_supply_changed(&chip->usb_psy);
power_supply_changed(&chip->batt_psy);
pm8921_bms_calibrate_hkadc();
-
- /* Enable/disable bypass if charger is on battery */
- if (chip->lockup_lpm_wrkarnd)
- pm8921_chg_bypass_bat_gone_debounce(chip,
- is_chg_on_bat(chip));
}
if (usb_present) {
schedule_delayed_work(&chip->unplug_check_work,
@@ -2496,10 +2231,6 @@
static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
{
- if (chip->lockup_lpm_wrkarnd)
- /* Enable bypass if charger is on battery */
- pm8921_chg_bypass_bat_gone_debounce(chip, is_chg_on_bat(chip));
-
if (!chip->ext_psy) {
pr_debug("external charger not registered.\n");
return;
@@ -2529,10 +2260,6 @@
unsigned long delay =
round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
- /* Disable bypass if charger connected and not running on bat */
- if (chip->lockup_lpm_wrkarnd)
- pm8921_chg_bypass_bat_gone_debounce(chip, is_chg_on_bat(chip));
-
if (!chip->ext_psy) {
pr_debug("external charger not registered.\n");
return;
@@ -3014,28 +2741,12 @@
pm_chg_get_fsm_state(chip),
get_prop_batt_current(chip)
);
- if (chip->lockup_lpm_wrkarnd) {
- rc = pm8921_apply_19p2mhz_kickstart(chip);
- if (rc)
- pr_err("Failed kickstart rc=%d\n", rc);
-
- /*
- * Make sure kickstart happens at least 200 ms
- * after charger has been removed.
- */
- if (chip->final_kickstart) {
- chip->final_kickstart = false;
- goto check_again_later;
- }
- }
return;
} else {
goto check_again_later;
}
}
- chip->final_kickstart = true;
-
/* AICL only for usb wall charger */
if ((active_path & USB_ACTIVE_BIT) && usb_target_ma > 0 &&
!chip->disable_aicl) {
@@ -3057,7 +2768,7 @@
pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
ibat = get_prop_batt_current(chip);
- if (reg_loop & VIN_ACTIVE_BIT) {
+ if ((reg_loop & VIN_ACTIVE_BIT) && !chip->disable_chg_rmvl_wrkarnd) {
if (ibat > 0) {
pr_debug("revboost ibat = %d fsm = %d loop = 0x%x\n",
ibat, pm_chg_get_fsm_state(chip), reg_loop);
@@ -3077,7 +2788,8 @@
active_path, active_chg_plugged_in);
chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
- if (chg_gone == 1 && active_chg_plugged_in == 1) {
+ if (chg_gone == 1 && active_chg_plugged_in == 1 &&
+ !chip->disable_chg_rmvl_wrkarnd) {
pr_debug("chg_gone=%d, active_chg_plugged_in = %d\n",
chg_gone, active_chg_plugged_in);
unplug_ovp_fet_open(chip);
@@ -3328,11 +3040,6 @@
else
handle_stop_ext_chg(chip);
} else {
- if (chip->lockup_lpm_wrkarnd)
- /* if no external supply call bypass debounce here */
- pm8921_chg_bypass_bat_gone_debounce(chip,
- is_chg_on_bat(chip));
-
if (dc_present)
schedule_delayed_work(&chip->unplug_check_work,
msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
@@ -4164,6 +3871,91 @@
return -EINVAL;
}
+static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
+{
+ int err;
+ u8 temp;
+
+ temp = 0xD1;
+ err = pm_chg_write(chip, CHG_TEST, temp);
+ if (err) {
+ pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+ return;
+ }
+
+ temp = 0xD3;
+ err = pm_chg_write(chip, CHG_TEST, temp);
+ if (err) {
+ pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+ return;
+ }
+
+ temp = 0xD1;
+ err = pm_chg_write(chip, CHG_TEST, temp);
+ if (err) {
+ pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+ return;
+ }
+
+ temp = 0xD5;
+ err = pm_chg_write(chip, CHG_TEST, temp);
+ if (err) {
+ pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+ return;
+ }
+
+ udelay(183);
+
+ temp = 0xD1;
+ err = pm_chg_write(chip, CHG_TEST, temp);
+ if (err) {
+ pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+ return;
+ }
+
+ temp = 0xD0;
+ err = pm_chg_write(chip, CHG_TEST, temp);
+ if (err) {
+ pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+ return;
+ }
+ udelay(32);
+
+ temp = 0xD1;
+ err = pm_chg_write(chip, CHG_TEST, temp);
+ if (err) {
+ pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+ return;
+ }
+
+ temp = 0xD3;
+ err = pm_chg_write(chip, CHG_TEST, temp);
+ if (err) {
+ pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+ return;
+ }
+}
+
+static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
+{
+ int err;
+ u8 temp;
+
+ temp = 0xD1;
+ err = pm_chg_write(chip, CHG_TEST, temp);
+ if (err) {
+ pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+ return;
+ }
+
+ temp = 0xD0;
+ err = pm_chg_write(chip, CHG_TEST, temp);
+ if (err) {
+ pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+ return;
+ }
+}
+
#define VREF_BATT_THERM_FORCE_ON BIT(7)
static void detect_battery_removal(struct pm8921_chg_chip *chip)
{
@@ -4195,15 +3987,8 @@
u8 subrev;
int rc, vdd_safe, fcc_uah, safety_time = DEFAULT_SAFETY_MINUTES;
- spin_lock_init(&lpm_lock);
-
- if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
- rc = __pm8921_apply_19p2mhz_kickstart(chip);
- if (rc) {
- pr_err("Failed to apply kickstart rc=%d\n", rc);
- return rc;
- }
- }
+ /* forcing 19p2mhz before accessing any charger registers */
+ pm8921_chg_force_19p2mhz_clk(chip);
detect_battery_removal(chip);
@@ -4451,45 +4236,6 @@
return rc;
}
- if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
- /* Clear kickstart */
- rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, 0xD0);
- if (rc) {
- pr_err("Failed to clear kickstart rc=%d\n", rc);
- return rc;
- }
-
- /* From here the lpm_workaround will be active */
- chip->lockup_lpm_wrkarnd = true;
-
- /* Enable LPM */
- pm8921_chg_set_lpm(chip, 1);
- }
-
- if (chip->lockup_lpm_wrkarnd) {
- chip->vreg_xoadc = regulator_get(chip->dev, "vreg_xoadc");
- if (IS_ERR(chip->vreg_xoadc))
- return -ENODEV;
-
- rc = regulator_set_optimum_mode(chip->vreg_xoadc, 10000);
- if (rc < 0) {
- pr_err("Failed to set configure HPM rc=%d\n", rc);
- return rc;
- }
-
- rc = regulator_set_voltage(chip->vreg_xoadc, 1800000, 1800000);
- if (rc) {
- pr_err("Failed to set L14 voltage rc=%d\n", rc);
- return rc;
- }
-
- rc = regulator_enable(chip->vreg_xoadc);
- if (rc) {
- pr_err("Failed to enable L14 rc=%d\n", rc);
- return rc;
- }
- }
-
return 0;
}
@@ -4740,19 +4486,16 @@
int rc;
struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
- if (chip->lockup_lpm_wrkarnd) {
- rc = regulator_disable(chip->vreg_xoadc);
- if (rc)
- pr_err("Failed to disable L14 rc=%d\n", rc);
-
- rc = pm8921_apply_19p2mhz_kickstart(chip);
- if (rc)
- pr_err("Failed to apply kickstart rc=%d\n", rc);
- }
-
rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
if (rc)
pr_err("Failed to Force Vref therm off rc=%d\n", rc);
+
+ rc = pm8921_chg_set_lpm(chip, 1);
+ if (rc)
+ pr_err("Failed to set lpm rc=%d\n", rc);
+
+ pm8921_chg_set_hw_clk_switching(chip);
+
return 0;
}
@@ -4761,15 +4504,11 @@
int rc;
struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
- if (chip->lockup_lpm_wrkarnd) {
- rc = regulator_enable(chip->vreg_xoadc);
- if (rc)
- pr_err("Failed to enable L14 rc=%d\n", rc);
+ pm8921_chg_force_19p2mhz_clk(chip);
- rc = pm8921_apply_19p2mhz_kickstart(chip);
- if (rc)
- pr_err("Failed to apply kickstart rc=%d\n", rc);
- }
+ rc = pm8921_chg_set_lpm(chip, 0);
+ if (rc)
+ pr_err("Failed to set lpm rc=%d\n", rc);
rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
VREF_BATT_THERM_FORCE_ON);
@@ -4869,6 +4608,7 @@
chip->vin_min = pdata->vin_min;
chip->thermal_mitigation = pdata->thermal_mitigation;
chip->thermal_levels = pdata->thermal_levels;
+ chip->disable_chg_rmvl_wrkarnd = pdata->disable_chg_rmvl_wrkarnd;
chip->cold_thr = pdata->cold_thr;
chip->hot_thr = pdata->hot_thr;
@@ -5000,7 +4740,6 @@
{
struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
- regulator_put(chip->vreg_xoadc);
free_irqs(chip);
platform_set_drvdata(pdev, NULL);
the_chip = NULL;
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index e2ba042..7833afa 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -86,8 +86,8 @@
#define USB_OVP_CTL 0x42
#define SEC_ACCESS 0xD0
-/* SMBB peripheral subtype values */
#define REG_OFFSET_PERP_SUBTYPE 0x05
+/* SMBB peripheral subtype values */
#define SMBB_CHGR_SUBTYPE 0x01
#define SMBB_BUCK_SUBTYPE 0x02
#define SMBB_BAT_IF_SUBTYPE 0x03
@@ -96,6 +96,14 @@
#define SMBB_BOOST_SUBTYPE 0x06
#define SMBB_MISC_SUBTYPE 0x07
+/* SMBB peripheral subtype values */
+#define SMBBP_CHGR_SUBTYPE 0x31
+#define SMBBP_BUCK_SUBTYPE 0x32
+#define SMBBP_BAT_IF_SUBTYPE 0x33
+#define SMBBP_USB_CHGPTH_SUBTYPE 0x34
+#define SMBBP_BOOST_SUBTYPE 0x36
+#define SMBBP_MISC_SUBTYPE 0x37
+
#define QPNP_CHARGER_DEV_NAME "qcom,qpnp-charger"
/* Status bits and masks */
@@ -341,6 +349,9 @@
u8 dcin_valid_rt_sts;
int rc;
+ if (!chip->dc_chgpth_base)
+ return 0;
+
rc = qpnp_chg_read(chip, &dcin_valid_rt_sts,
INT_RT_STS(chip->dc_chgpth_base), 1);
if (rc) {
@@ -1212,6 +1223,7 @@
switch (subtype) {
case SMBB_CHGR_SUBTYPE:
+ case SMBBP_CHGR_SUBTYPE:
chip->chg_done_irq = spmi_get_irq_byname(chip->spmi,
spmi_resource, "chg-done");
if (chip->chg_done_irq < 0) {
@@ -1289,6 +1301,7 @@
enable_irq_wake(chip->chg_done_irq);
break;
case SMBB_BUCK_SUBTYPE:
+ case SMBBP_BUCK_SUBTYPE:
rc = qpnp_chg_masked_write(chip,
chip->chgr_base + CHGR_BUCK_BCK_VBAT_REG_MODE,
BUCK_VBAT_REG_NODE_SEL_BIT,
@@ -1299,8 +1312,10 @@
}
break;
case SMBB_BAT_IF_SUBTYPE:
+ case SMBBP_BAT_IF_SUBTYPE:
break;
case SMBB_USB_CHGPTH_SUBTYPE:
+ case SMBBP_USB_CHGPTH_SUBTYPE:
chip->usbin_valid_irq = spmi_get_irq_byname(chip->spmi,
spmi_resource, "usbin-valid");
if (chip->usbin_valid_irq < 0) {
@@ -1361,8 +1376,10 @@
enable_irq_wake(chip->dcin_valid_irq);
break;
case SMBB_BOOST_SUBTYPE:
+ case SMBBP_BOOST_SUBTYPE:
break;
case SMBB_MISC_SUBTYPE:
+ case SMBBP_MISC_SUBTYPE:
pr_debug("Setting BOOT_DONE\n");
rc = qpnp_chg_masked_write(chip,
chip->misc_base + CHGR_MISC_BOOT_DONE,
@@ -1397,10 +1414,6 @@
return -ENOMEM;
}
- rc = qpnp_vadc_is_ready();
- if (rc)
- goto fail_chg_enable;
-
chip->dev = &(spmi->dev);
chip->spmi = spmi;
@@ -1557,6 +1570,7 @@
switch (subtype) {
case SMBB_CHGR_SUBTYPE:
+ case SMBBP_CHGR_SUBTYPE:
chip->chgr_base = resource->start;
rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
if (rc) {
@@ -1566,6 +1580,7 @@
}
break;
case SMBB_BUCK_SUBTYPE:
+ case SMBBP_BUCK_SUBTYPE:
chip->buck_base = resource->start;
rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
if (rc) {
@@ -1575,6 +1590,7 @@
}
break;
case SMBB_BAT_IF_SUBTYPE:
+ case SMBBP_BAT_IF_SUBTYPE:
chip->bat_if_base = resource->start;
rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
if (rc) {
@@ -1584,6 +1600,7 @@
}
break;
case SMBB_USB_CHGPTH_SUBTYPE:
+ case SMBBP_USB_CHGPTH_SUBTYPE:
chip->usb_chgpth_base = resource->start;
rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
if (rc) {
@@ -1602,6 +1619,7 @@
}
break;
case SMBB_BOOST_SUBTYPE:
+ case SMBBP_BOOST_SUBTYPE:
chip->boost_base = resource->start;
rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
if (rc) {
@@ -1611,6 +1629,7 @@
}
break;
case SMBB_MISC_SUBTYPE:
+ case SMBBP_MISC_SUBTYPE:
chip->misc_base = resource->start;
rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
if (rc) {
@@ -1628,34 +1647,44 @@
dev_set_drvdata(&spmi->dev, chip);
device_init_wakeup(&spmi->dev, 1);
- chip->dc_psy.name = "qpnp-dc";
- chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
- chip->dc_psy.supplied_to = pm_power_supplied_to;
- chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
- chip->dc_psy.properties = pm_power_props_mains;
- chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains);
- chip->dc_psy.get_property = qpnp_power_get_property_mains;
+ if (chip->bat_if_base) {
+ rc = qpnp_vadc_is_ready();
+ if (rc)
+ goto fail_chg_enable;
- chip->batt_psy.name = "battery";
- chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
- chip->batt_psy.properties = msm_batt_power_props;
- chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props);
- chip->batt_psy.get_property = qpnp_batt_power_get_property;
- chip->batt_psy.set_property = qpnp_batt_power_set_property;
- chip->batt_psy.property_is_writeable = qpnp_batt_property_is_writeable;
- chip->batt_psy.external_power_changed =
+ chip->batt_psy.name = "battery";
+ chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
+ chip->batt_psy.properties = msm_batt_power_props;
+ chip->batt_psy.num_properties =
+ ARRAY_SIZE(msm_batt_power_props);
+ chip->batt_psy.get_property = qpnp_batt_power_get_property;
+ chip->batt_psy.set_property = qpnp_batt_power_set_property;
+ chip->batt_psy.property_is_writeable =
+ qpnp_batt_property_is_writeable;
+ chip->batt_psy.external_power_changed =
qpnp_batt_external_power_changed;
- rc = power_supply_register(chip->dev, &chip->batt_psy);
- if (rc < 0) {
- pr_err("power_supply_register batt failed rc = %d\n", rc);
- goto fail_chg_enable;
+ rc = power_supply_register(chip->dev, &chip->batt_psy);
+ if (rc < 0) {
+ pr_err("batt failed to register rc = %d\n", rc);
+ goto fail_chg_enable;
+ }
}
- rc = power_supply_register(chip->dev, &chip->dc_psy);
- if (rc < 0) {
- pr_err("power_supply_register usb failed rc = %d\n", rc);
- goto unregister_batt;
+ if (chip->dc_chgpth_base) {
+ chip->dc_psy.name = "qpnp-dc";
+ chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
+ chip->dc_psy.supplied_to = pm_power_supplied_to;
+ chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
+ chip->dc_psy.properties = pm_power_props_mains;
+ chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains);
+ chip->dc_psy.get_property = qpnp_power_get_property_mains;
+
+ rc = power_supply_register(chip->dev, &chip->dc_psy);
+ if (rc < 0) {
+ pr_err("power_supply_register dc failed rc=%d\n", rc);
+ goto unregister_batt;
+ }
}
/* Turn on appropriate workaround flags */
@@ -1664,11 +1693,11 @@
power_supply_set_present(chip->usb_psy,
qpnp_chg_is_usb_chg_plugged_in(chip));
- if (chip->maxinput_dc_ma) {
+ if (chip->maxinput_dc_ma && chip->dc_chgpth_base) {
rc = qpnp_chg_idcmax_set(chip, chip->maxinput_dc_ma);
if (rc) {
pr_err("Error setting idcmax property %d\n", rc);
- goto fail_chg_enable;
+ goto unregister_batt;
}
}
@@ -1684,7 +1713,8 @@
return 0;
unregister_batt:
- power_supply_unregister(&chip->batt_psy);
+ if (chip->bat_if_base)
+ power_supply_unregister(&chip->batt_psy);
fail_chg_enable:
kfree(chip->thermal_mitigation);
kfree(chip);
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index 40e1eea..faa5625 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -45,6 +45,7 @@
struct ehci_hcd ehci;
spinlock_t wakeup_lock;
struct device *dev;
+ struct clk *xo_clk;
struct clk *iface_clk;
struct clk *core_clk;
struct clk *alt_core_clk;
@@ -659,10 +660,14 @@
clk_disable_unprepare(mhcd->core_clk);
/* usb phy does not require TCXO clock, hence vote for TCXO disable */
- ret = msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_OFF);
- if (ret)
- dev_err(mhcd->dev, "%s failed to devote for "
- "TCXO D0 buffer%d\n", __func__, ret);
+ if (!IS_ERR(mhcd->xo_clk)) {
+ clk_disable_unprepare(mhcd->xo_clk);
+ } else {
+ ret = msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_OFF);
+ if (ret)
+ dev_err(mhcd->dev, "%s failed to devote for TCXO %d\n",
+ __func__, ret);
+ }
msm_ehci_config_vddcx(mhcd, 0);
@@ -714,10 +719,14 @@
wake_lock(&mhcd->wlock);
/* Vote for TCXO when waking up the phy */
- ret = msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_ON);
- if (ret)
- dev_err(mhcd->dev, "%s failed to vote for "
- "TCXO D0 buffer%d\n", __func__, ret);
+ if (!IS_ERR(mhcd->xo_clk)) {
+ clk_prepare_enable(mhcd->xo_clk);
+ } else {
+ ret = msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_ON);
+ if (ret)
+ dev_err(mhcd->dev, "%s failed to vote for TCXO D0 %d\n",
+ __func__, ret);
+ }
clk_prepare_enable(mhcd->core_clk);
clk_prepare_enable(mhcd->iface_clk);
@@ -1091,18 +1100,23 @@
}
snprintf(pdev_name, PDEV_NAME_LEN, "%s.%d", pdev->name, pdev->id);
- mhcd->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, pdev_name);
- if (IS_ERR(mhcd->xo_handle)) {
- dev_err(&pdev->dev, "%s not able to get the handle "
- "to vote for TCXO D0 buffer\n", __func__);
- ret = PTR_ERR(mhcd->xo_handle);
- goto free_async_irq;
+ mhcd->xo_clk = clk_get(&pdev->dev, "xo");
+ if (!IS_ERR(mhcd->xo_clk)) {
+ ret = clk_prepare_enable(mhcd->xo_clk);
+ } else {
+ mhcd->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, pdev_name);
+ if (IS_ERR(mhcd->xo_handle)) {
+ dev_err(&pdev->dev, "%s fail to get handle for X0 D0\n",
+ __func__);
+ ret = PTR_ERR(mhcd->xo_handle);
+ goto free_async_irq;
+ } else {
+ ret = msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_ON);
+ }
}
-
- ret = msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_ON);
if (ret) {
- dev_err(&pdev->dev, "%s failed to vote for TCXO "
- "D0 buffer%d\n", __func__, ret);
+ dev_err(&pdev->dev, "%s failed to vote for TCXO %d\n",
+ __func__, ret);
goto free_xo_handle;
}
@@ -1202,9 +1216,15 @@
deinit_clocks:
msm_ehci_init_clocks(mhcd, 0);
devote_xo_handle:
- msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_OFF);
+ if (!IS_ERR(mhcd->xo_clk))
+ clk_disable_unprepare(mhcd->xo_clk);
+ else
+ msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_OFF);
free_xo_handle:
- msm_xo_put(mhcd->xo_handle);
+ if (!IS_ERR(mhcd->xo_clk))
+ clk_put(mhcd->xo_clk);
+ else
+ msm_xo_put(mhcd->xo_handle);
free_async_irq:
if (mhcd->async_irq)
free_irq(mhcd->async_irq, mhcd);
@@ -1236,7 +1256,12 @@
usb_remove_hcd(hcd);
- msm_xo_put(mhcd->xo_handle);
+ if (!IS_ERR(mhcd->xo_clk)) {
+ clk_disable_unprepare(mhcd->xo_clk);
+ clk_put(mhcd->xo_clk);
+ } else {
+ msm_xo_put(mhcd->xo_handle);
+ }
msm_ehci_vbus_power(mhcd, 0);
msm_ehci_init_vbus(mhcd, 0);
msm_ehci_ldo_enable(mhcd, 0);
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 06772d9..f6ca334 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -385,6 +385,7 @@
header-y += types.h
header-y += udf_fs_i.h
header-y += udp.h
+header-y += uhid.h
header-y += uinput.h
header-y += uio.h
header-y += ultrasound.h
@@ -450,3 +451,4 @@
header-y += ci-bridge-spi.h
header-y += msm_audio_amrwbplus.h
header-y += avtimer.h
+header-y += msm_ipa.h
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 785a33a..1c67b1e 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. 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
@@ -188,6 +188,7 @@
int btc_delay_ms;
int btc_panic_if_cant_stop_chg;
int stop_chg_upon_expiry;
+ bool disable_chg_rmvl_wrkarnd;
};
enum pm8921_charger_source {
diff --git a/include/linux/uhid.h b/include/linux/uhid.h
new file mode 100644
index 0000000..16b786a
--- /dev/null
+++ b/include/linux/uhid.h
@@ -0,0 +1,33 @@
+#ifndef __UHID_H_
+#define __UHID_H_
+
+/*
+ * User-space I/O driver support for HID subsystem
+ * Copyright (c) 2012 David Herrmann
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+/*
+ * Public header for user-space communication. We try to keep every structure
+ * aligned but to be safe we also use __attribute__((__packed__)). Therefore,
+ * the communication should be ABI compatible even between architectures.
+ */
+
+#include <linux/input.h>
+#include <linux/types.h>
+
+enum uhid_event_type {
+ UHID_DUMMY,
+};
+
+struct uhid_event {
+ __u32 type;
+} __attribute__((__packed__));
+
+#endif /* __UHID_H_ */
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index 0b26a56..25d3f56 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -487,16 +487,16 @@
SOC_ENUM_SINGLE(TAPAN_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
static const struct soc_enum cf_rxmix1_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_RX1_B4_CTL, 0, 3, cf_text);
static const struct soc_enum cf_rxmix2_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_RX2_B4_CTL, 1, 3, cf_text);
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_RX2_B4_CTL, 0, 3, cf_text);
static const struct soc_enum cf_rxmix3_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_RX3_B4_CTL, 1, 3, cf_text);
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_RX3_B4_CTL, 0, 3, cf_text);
static const struct soc_enum cf_rxmix4_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_RX4_B4_CTL, 1, 3, cf_text);
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_RX4_B4_CTL, 0, 3, cf_text);
static const struct snd_kcontrol_new tapan_snd_controls[] = {
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index f48dbf1..7f17eef 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -829,25 +829,25 @@
SOC_ENUM_SINGLE(TAIKO_A_CDC_TX10_MUX_CTL, 4, 3, cf_text);
static const struct soc_enum cf_rxmix1_enum =
- SOC_ENUM_SINGLE(TAIKO_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_RX1_B4_CTL, 0, 3, cf_text);
static const struct soc_enum cf_rxmix2_enum =
- SOC_ENUM_SINGLE(TAIKO_A_CDC_RX2_B4_CTL, 1, 3, cf_text);
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_RX2_B4_CTL, 0, 3, cf_text);
static const struct soc_enum cf_rxmix3_enum =
- SOC_ENUM_SINGLE(TAIKO_A_CDC_RX3_B4_CTL, 1, 3, cf_text);
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_RX3_B4_CTL, 0, 3, cf_text);
static const struct soc_enum cf_rxmix4_enum =
- SOC_ENUM_SINGLE(TAIKO_A_CDC_RX4_B4_CTL, 1, 3, cf_text);
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_RX4_B4_CTL, 0, 3, cf_text);
static const struct soc_enum cf_rxmix5_enum =
- SOC_ENUM_SINGLE(TAIKO_A_CDC_RX5_B4_CTL, 1, 3, cf_text)
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_RX5_B4_CTL, 0, 3, cf_text)
;
static const struct soc_enum cf_rxmix6_enum =
- SOC_ENUM_SINGLE(TAIKO_A_CDC_RX6_B4_CTL, 1, 3, cf_text);
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_RX6_B4_CTL, 0, 3, cf_text);
static const struct soc_enum cf_rxmix7_enum =
- SOC_ENUM_SINGLE(TAIKO_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_RX7_B4_CTL, 0, 3, cf_text);
static const char * const class_h_dsm_text[] = {
"ZERO", "DSM_HPHL_RX1", "DSM_SPKR_RX7"
diff --git a/sound/soc/msm/mdm9625.c b/sound/soc/msm/mdm9625.c
index eb7366c..2bef1b7 100644
--- a/sound/soc/msm/mdm9625.c
+++ b/sound/soc/msm/mdm9625.c
@@ -749,7 +749,7 @@
.name = "MDM9625 Media1",
.stream_name = "MultiMedia1",
.cpu_dai_name = "MultiMedia1",
- .platform_name = "msm-pcm-dsp",
+ .platform_name = "msm-pcm-dsp.0",
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},