Merge "msm: smd: Clear Apps SMSM_RESET for Subsytem Restart" into msm-3.0
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index 84cd633..cc9a1b7 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -332,6 +332,7 @@
CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
+CONFIG_MSM_KGSL_PAGE_TABLE_COUNT=16
CONFIG_VIDEO_OUTPUT_CONTROL=y
CONFIG_FB=y
CONFIG_FB_MSM=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 50b4b08..eb34964 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -332,6 +332,7 @@
CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
+CONFIG_MSM_KGSL_PAGE_TABLE_COUNT=16
CONFIG_VIDEO_OUTPUT_CONTROL=y
CONFIG_FB=y
CONFIG_FB_MSM=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 9feca99..d8d2e35 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -309,6 +309,7 @@
CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
+CONFIG_MSM_KGSL_PAGE_TABLE_COUNT=16
CONFIG_FB=y
CONFIG_FB_VIRTUAL=y
CONFIG_FB_MSM=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 1d506e4..5e90492 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -312,6 +312,7 @@
CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
+CONFIG_MSM_KGSL_PAGE_TABLE_COUNT=16
CONFIG_FB=y
CONFIG_FB_VIRTUAL=y
CONFIG_FB_MSM=y
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 76f86d7..738a166 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -266,6 +266,7 @@
{
struct thread_info *thread = current_thread_info();
int ret;
+ enum bug_trap_type bug_type = BUG_TRAP_TYPE_NONE;
oops_enter();
@@ -273,7 +274,9 @@
console_verbose();
bust_spinlocks(1);
if (!user_mode(regs))
- report_bug(regs->ARM_pc, regs);
+ bug_type = report_bug(regs->ARM_pc, regs);
+ if (bug_type != BUG_TRAP_TYPE_NONE)
+ str = "Oops - BUG";
ret = __die(str, err, thread, regs);
if (regs && kexec_should_crash(thread->task))
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index e6d9447..cc6f18f 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -1370,7 +1370,6 @@
tx_mem_failed:
sps_deregister_bam_device(h);
register_bam_failed:
- iounmap(a2_virt_addr);
ioremap_failed:
/*destroy_workqueue(bam_mux_workqueue);*/
return ret;
@@ -1409,7 +1408,6 @@
return 0;
register_bam_failed:
- iounmap(a2_virt_addr);
ioremap_failed:
return ret;
}
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index b9ac4b8..e9c41d8 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.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
@@ -188,7 +188,7 @@
static struct pm8xxx_pwrkey_platform_data pm8xxx_pwrkey_pdata = {
.pull_up = 1,
- .kpd_trigger_delay_us = 970,
+ .kpd_trigger_delay_us = 15625,
.wakeup = 1,
};
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
index d3e19a0..f383f31 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -50,12 +50,14 @@
};
VREG_CONSUMERS(L9) = {
REGULATOR_SUPPLY("8038_l9", NULL),
+ REGULATOR_SUPPLY("vdd_ana", "3-004a"),
};
VREG_CONSUMERS(L10) = {
REGULATOR_SUPPLY("8038_l10", NULL),
};
VREG_CONSUMERS(L11) = {
REGULATOR_SUPPLY("8038_l11", NULL),
+ REGULATOR_SUPPLY("vdd_dig", "3-004a"),
};
VREG_CONSUMERS(L12) = {
REGULATOR_SUPPLY("8038_l12", NULL),
@@ -128,6 +130,7 @@
};
VREG_CONSUMERS(LVS2) = {
REGULATOR_SUPPLY("8038_lvs2", NULL),
+ REGULATOR_SUPPLY("vcc_i2c", "3-004a"),
};
VREG_CONSUMERS(EXT_5V) = {
REGULATOR_SUPPLY("ext_5v", NULL),
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index fb4cc52..1b4b999 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -1338,6 +1338,9 @@
.x_size = 1067,
.y_size = 566,
.irqflags = IRQF_TRIGGER_FALLING,
+#ifdef MSM8930_PHASE_2
+ .digital_pwr_regulator = true,
+#endif
.i2c_pull_up = true,
.reset_gpio = MXT_TS_RESET_GPIO,
.irq_gpio = MXT_TS_GPIO_IRQ,
diff --git a/arch/arm/mach-msm/board-8960-gpiomux.c b/arch/arm/mach-msm/board-8960-gpiomux.c
index 71713829..0dfa1c6 100644
--- a/arch/arm/mach-msm/board-8960-gpiomux.c
+++ b/arch/arm/mach-msm/board-8960-gpiomux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* 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
@@ -84,7 +84,7 @@
{
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_NONE,
+ .pull = GPIOMUX_PULL_DOWN,
},
/* Active state */
{
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index f6212af..f36c3a1 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -499,7 +499,7 @@
RPM_SMPS(S1, 1, 1, 0, 1225000, 1225000, NULL, 100000, 3p20),
RPM_SMPS(S2, 0, 1, 0, 1300000, 1300000, NULL, 0, 1p60),
RPM_SMPS(S3, 0, 1, 1, 500000, 1150000, NULL, 100000, 4p80),
- RPM_SMPS(S4, 1, 1, 0, 1800000, 1800000, NULL, 100000, 3p20),
+ RPM_SMPS(S4, 1, 1, 0, 1800000, 1800000, NULL, 100000, 1p60),
RPM_SMPS(S7, 0, 1, 0, 1150000, 1150000, NULL, 100000, 3p20),
RPM_SMPS(S8, 1, 1, 1, 2100000, 2100000, NULL, 100000, 1p60),
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 02659b2..3881019 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -1362,6 +1362,8 @@
/* T15 Object */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
+ /* T18 Object */
+ 0, 0,
/* T22 Object */
5, 0, 0, 0, 0, 0, 0, 0, 30, 0,
0, 0, 5, 8, 10, 13, 0,
diff --git a/arch/arm/mach-msm/devices-msm7x27.c b/arch/arm/mach-msm/devices-msm7x27.c
index 0fb64dc..cdb43ad 100644
--- a/arch/arm/mach-msm/devices-msm7x27.c
+++ b/arch/arm/mach-msm/devices-msm7x27.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -18,6 +18,7 @@
#include <linux/msm_kgsl.h>
#include <linux/regulator/machine.h>
#include <linux/dma-mapping.h>
+#include <linux/init.h>
#include <asm/clkdev.h>
#include <mach/irqs.h>
#include <mach/msm_iomap.h>
@@ -839,3 +840,29 @@
FS_PCOM(FS_GFX3D, "fs_gfx3d"),
};
unsigned msm_num_footswitch_devices = ARRAY_SIZE(msm_footswitch_devices);
+
+static struct resource gpio_resources[] = {
+ {
+ .start = INT_GPIO_GROUP1,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = INT_GPIO_GROUP2,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device msm_device_gpio = {
+ .name = "msmgpio",
+ .id = -1,
+ .resource = gpio_resources,
+ .num_resources = ARRAY_SIZE(gpio_resources),
+};
+
+static int __init msm7627_init_gpio(void)
+{
+ platform_device_register(&msm_device_gpio);
+ return 0;
+}
+
+postcore_initcall(msm7627_init_gpio);
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 8a090f8..917dfc7 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.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
@@ -15,6 +15,7 @@
#include <linux/dma-mapping.h>
#include <linux/msm_kgsl.h>
#include <linux/regulator/machine.h>
+#include <linux/init.h>
#include <mach/irqs.h>
#include <mach/msm_iomap.h>
#include <mach/board.h>
@@ -696,6 +697,31 @@
.id = 0,
};
+static struct resource gpio_resources[] = {
+ {
+ .start = INT_GPIO_GROUP1,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = INT_GPIO_GROUP2,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device msm_device_gpio = {
+ .name = "msmgpio",
+ .id = -1,
+ .resource = gpio_resources,
+ .num_resources = ARRAY_SIZE(gpio_resources),
+};
+
+static int msm7627a_init_gpio(void)
+{
+ platform_device_register(&msm_device_gpio);
+ return 0;
+}
+postcore_initcall(msm7627a_init_gpio);
+
int __init msm7x2x_misc_init(void)
{
msm_clock_init(&msm7x27a_clock_init_data);
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index 2c21f57..db656f3 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -20,6 +20,7 @@
#include <linux/msm_kgsl.h>
#include <linux/android_pmem.h>
#include <linux/regulator/machine.h>
+#include <linux/init.h>
#include <mach/irqs.h>
#include <mach/msm_iomap.h>
#include <mach/dma.h>
@@ -1187,3 +1188,29 @@
FS_PCOM(FS_VPE, "fs_vpe"),
};
unsigned msm_num_footswitch_devices = ARRAY_SIZE(msm_footswitch_devices);
+
+static struct resource gpio_resources[] = {
+ {
+ .start = INT_GPIO_GROUP1,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = INT_GPIO_GROUP2,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device msm_device_gpio = {
+ .name = "msmgpio",
+ .id = -1,
+ .resource = gpio_resources,
+ .num_resources = ARRAY_SIZE(gpio_resources),
+};
+
+static int __init msm7630_init_gpio(void)
+{
+ platform_device_register(&msm_device_gpio);
+ return 0;
+}
+
+postcore_initcall(msm7630_init_gpio);
diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c
index a942862..ea9e0d5 100644
--- a/arch/arm/mach-msm/gpio.c
+++ b/arch/arm/mach-msm/gpio.c
@@ -1,7 +1,7 @@
/* linux/arch/arm/mach-msm/gpio.c
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -20,6 +20,7 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/module.h>
+#include <linux/platform_device.h>
#include <asm/mach/irq.h>
#include <mach/gpiomux.h>
#include "gpio_hw.h"
@@ -486,37 +487,6 @@
}
}
-static int __init msm_init_gpio(void)
-{
- int i, j = 0;
-
- for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
- if (i - FIRST_GPIO_IRQ >=
- msm_gpio_chips[j].chip.base +
- msm_gpio_chips[j].chip.ngpio)
- j++;
- irq_set_chip_data(i, &msm_gpio_chips[j]);
- irq_set_chip_and_handler(i, &msm_gpio_irq_chip,
- handle_edge_irq);
- set_irq_flags(i, IRQF_VALID);
- }
-
- irq_set_chained_handler(INT_GPIO_GROUP1, msm_gpio_irq_handler);
- irq_set_chained_handler(INT_GPIO_GROUP2, msm_gpio_irq_handler);
-
- for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
- spin_lock_init(&msm_gpio_chips[i].lock);
- __raw_writel(0, msm_gpio_chips[i].regs.int_en);
- gpiochip_add(&msm_gpio_chips[i].chip);
- }
-
- mb();
- irq_set_irq_wake(INT_GPIO_GROUP1, 1);
- irq_set_irq_wake(INT_GPIO_GROUP2, 2);
- return 0;
-}
-
-postcore_initcall(msm_init_gpio);
int gpio_tlmm_config(unsigned config, unsigned disable)
{
@@ -643,3 +613,52 @@
*out = msm_chip->regs.out;
*offset = gpio - msm_chip->chip.base;
}
+
+static int __devinit msm_gpio_probe(struct platform_device *dev)
+{
+ int i, j = 0;
+ int grp_irq;
+
+ for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
+ if (i - FIRST_GPIO_IRQ >=
+ msm_gpio_chips[j].chip.base +
+ msm_gpio_chips[j].chip.ngpio)
+ j++;
+ irq_set_chip_data(i, &msm_gpio_chips[j]);
+ irq_set_chip_and_handler(i, &msm_gpio_irq_chip,
+ handle_edge_irq);
+ set_irq_flags(i, IRQF_VALID);
+ }
+
+ for (i = 0; i < dev->num_resources; i++) {
+ grp_irq = platform_get_irq(dev, i);
+ if (grp_irq < 0)
+ return -ENXIO;
+
+ irq_set_chained_handler(grp_irq, msm_gpio_irq_handler);
+ irq_set_irq_wake(grp_irq, (i + 1));
+ }
+
+ for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
+ spin_lock_init(&msm_gpio_chips[i].lock);
+ __raw_writel(0, msm_gpio_chips[i].regs.int_en);
+ gpiochip_add(&msm_gpio_chips[i].chip);
+ }
+
+ mb();
+ return 0;
+}
+
+static struct platform_driver msm_gpio_driver = {
+ .probe = msm_gpio_probe,
+ .driver = {
+ .name = "msmgpio",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_gpio_init(void)
+{
+ return platform_driver_register(&msm_gpio_driver);
+}
+postcore_initcall(msm_gpio_init);
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 6dfb354..8085b82 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -27,6 +27,7 @@
#include "pm.h"
#include "scm-boot.h"
+#include "spm.h"
int pen_release = -1;
@@ -90,6 +91,8 @@
if (!base_ptr)
return -ENODEV;
+ msm_spm_turn_on_cpu_rail(cpu);
+
writel_relaxed(0x109, base_ptr+0x04);
writel_relaxed(0x101, base_ptr+0x04);
ndelay(300);
diff --git a/arch/arm/mach-msm/spm.h b/arch/arm/mach-msm/spm.h
index 5825bcf..78fd922 100644
--- a/arch/arm/mach-msm/spm.h
+++ b/arch/arm/mach-msm/spm.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
@@ -110,6 +110,7 @@
void msm_spm_reinit(void);
void msm_spm_allow_x_cpu_set_vdd(bool allowed);
int msm_spm_init(struct msm_spm_platform_data *data, int nr_devs);
+int msm_spm_turn_on_cpu_rail(unsigned int cpu);
#if defined(CONFIG_MSM_L2_SPM)
int msm_spm_l2_set_low_power_mode(unsigned int mode, bool notify_rpm);
@@ -148,6 +149,10 @@
/* empty */
}
+static inline int msm_spm_turn_on_cpu_rail(unsigned int cpu)
+{
+ return -ENOSYS;
+}
#endif /*defined(CONFIG_MSM_SPM_V1) || defined (CONFIG_MSM_SPM_V2) */
#endif /* __ARCH_ARM_MACH_MSM_SPM_H */
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 6ea9327..326faef 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.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
@@ -162,6 +162,40 @@
return ret;
}
+int msm_spm_turn_on_cpu_rail(unsigned int cpu)
+{
+ uint32_t val = 0;
+ uint32_t timeout = 0;
+ void *reg = NULL;
+
+ if (cpu >= num_possible_cpus())
+ return -EINVAL;
+
+ switch (cpu) {
+ case 1:
+ reg = MSM_SAW1_BASE;
+ break;
+ case 0:
+ default:
+ return -EFAULT;
+ }
+
+ if (cpu_is_msm8960() || cpu_is_msm8930()) {
+ val = 0xB0;
+ reg += 0x14;
+ timeout = 512;
+ } else {
+ return -ENOSYS;
+ }
+
+ writel_relaxed(val, reg);
+ mb();
+ udelay(timeout);
+
+ return 0;
+}
+EXPORT_SYMBOL(msm_spm_turn_on_cpu_rail);
+
#if defined(CONFIG_MSM_L2_SPM)
static struct msm_spm_device msm_spm_l2_device;
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index f1d40ef..c13abff 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -2,7 +2,7 @@
* drivers/gpu/ion/ion_carveout_heap.c
*
* Copyright (C) 2011 Google, Inc.
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -401,6 +401,7 @@
ret = gen_pool_add(carveout_heap->pool, carveout_heap->base,
heap_data->size, -1);
if (ret < 0) {
+ gen_pool_destroy(carveout_heap->pool);
kfree(carveout_heap);
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 630de1d..2fa0b7a 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -509,7 +509,6 @@
void mdp4_overlay_lcdc_wait4vsync(struct msm_fb_data_type *mfd);
void mdp4_overlay_lcdc_vsync_push(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe);
-void mdp4_overlay_lcdc_set_perf(struct msm_fb_data_type *mfd);
void mdp4_update_perf_level(u32 perf_level);
void mdp4_set_perf_level(void);
void mdp4_mddi_overlay_dmas_restore(void);
@@ -620,7 +619,6 @@
void mdp4_dsi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd);
void mdp4_overlay_dsi_video_vsync_push(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe);
-void mdp4_overlay_dsi_video_set_perf(struct msm_fb_data_type *mfd);
#else
static inline void mdp4_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd)
{
@@ -635,11 +633,6 @@
{
/* empty */
}
-static inline void mdp4_overlay_dsi_video_set_perf(
- struct msm_fb_data_type *mfd)
-{
- /* empty */
-}
#endif /* MIPI_DSI */
void mdp4_dsi_cmd_kickoff_ui(struct msm_fb_data_type *mfd,
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index a53102a..51dd440 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -2205,18 +2205,21 @@
mdp4_overlay_dtv_set(mfd, pipe);
if (new_perf_level != perf_level) {
+ u32 old_level = new_perf_level;
mdp4_update_perf_level(perf_level);
/* change clck base on perf level */
if (pipe->mixer_num == MDP4_MIXER0) {
if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
- mdp4_overlay_dsi_video_set_perf(mfd);
+ if (old_level > perf_level)
+ mdp4_set_perf_level();
} else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
mdp4_dsi_cmd_dma_busy_wait(mfd);
mdp4_dsi_blt_dmap_busy_wait(mfd);
mdp4_set_perf_level();
} else if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
- mdp4_overlay_lcdc_set_perf(mfd);
+ if (old_level > perf_level)
+ mdp4_set_perf_level();
} else if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
mdp4_mddi_dma_busy_wait(mfd);
mdp4_set_perf_level();
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index c5d1b0c..88582e4 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -465,13 +465,6 @@
pr_debug("%s: done pid=%d\n", __func__, current->pid);
}
-void mdp4_overlay_dsi_video_set_perf(struct msm_fb_data_type *mfd)
-{
- mdp4_overlay_dsi_video_wait4event(mfd, INTR_DMA_P_DONE);
- /* change mdp clk while mdp is idle */
- mdp4_set_perf_level();
-}
-
void mdp4_overlay_dsi_video_vsync_push(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe)
{
@@ -499,9 +492,10 @@
mb();
mdp4_overlay_dsi_video_wait4event(mfd, INTR_DMA_P_DONE);
} else {
-
mdp4_overlay_dsi_video_wait4event(mfd, INTR_PRIMARY_VSYNC);
}
+
+ mdp4_set_perf_level();
}
/*
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index 592febe..f2065fd 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -358,6 +358,12 @@
mdp4_overlay_dmae_xy(pipe); /* dma_e */
mdp4_overlayproc_cfg(pipe);
+
+ if (pipe->pipe_type == OVERLAY_TYPE_RGB) {
+ pipe->srcp0_addr = (uint32) mfd->ibuf.buf;
+ mdp4_overlay_rgb_setup(pipe);
+ }
+
mdp4_mixer_stage_up(pipe);
dtv_pipe = pipe; /* keep it */
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index bef988c..a905ec0 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -385,13 +385,6 @@
pr_debug("%s: done pid=%d\n", __func__, current->pid);
}
-void mdp4_overlay_lcdc_set_perf(struct msm_fb_data_type *mfd)
-{
- mdp4_overlay_lcdc_wait4event(mfd, INTR_DMA_P_DONE);
- /* change mdp clk while mdp is idle */
- mdp4_set_perf_level();
-}
-
void mdp4_overlay_lcdc_vsync_push(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe)
{
@@ -421,6 +414,7 @@
} else {
mdp4_overlay_lcdc_wait4event(mfd, INTR_PRIMARY_VSYNC);
}
+ mdp4_set_perf_level();
}
/*
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
index cc35ea3..8eba8bd 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.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
@@ -15,6 +15,7 @@
#include "vcd_ddl.h"
#include "vcd_ddl_shared_mem.h"
#include "vcd_ddl_metadata.h"
+#include "vcd_res_tracker_api.h"
#include <linux/delay.h>
static void ddl_decoder_input_done_callback(
@@ -254,6 +255,13 @@
DDL_MSG_LOW("HEADER_DONE");
vidc_1080p_get_decode_seq_start_result(&seq_hdr_info);
parse_hdr_size_data(ddl, &seq_hdr_info);
+ if (res_trk_get_disable_fullhd() &&
+ (seq_hdr_info.img_size_x * seq_hdr_info.img_size_y >
+ 1280 * 720)) {
+ DDL_MSG_ERROR("FATAL:Resolution greater than 720P HD");
+ ddl_client_fatal_cb(ddl);
+ return process_further;
+ }
if (!seq_hdr_info.img_size_x || !seq_hdr_info.img_size_y) {
DDL_MSG_ERROR("FATAL:ZeroImageSize");
ddl_client_fatal_cb(ddl);
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
index 3a86afc..4f22706 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.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
@@ -441,6 +441,8 @@
}
resource_context.disable_dmx =
resource_context.vidc_platform_data->disable_dmx;
+ resource_context.disable_fullhd =
+ resource_context.vidc_platform_data->disable_fullhd;
#ifdef CONFIG_MSM_BUS_SCALING
resource_context.vidc_bus_client_pdata =
resource_context.vidc_platform_data->
@@ -513,3 +515,8 @@
resource_context.res_mem_type = mem_type;
return;
}
+
+u32 res_trk_get_disable_fullhd(void)
+{
+ return resource_context.disable_fullhd;
+}
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
index 7283991..be5045f 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.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
@@ -50,6 +50,7 @@
struct ddl_buf_addr firmware_addr;
struct ion_client *res_ion_client;
u32 disable_dmx;
+ u32 disable_fullhd;
enum ddl_mem_area res_mem_type;
};
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
index 47fa363..fd4ca3e 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.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
@@ -31,6 +31,7 @@
u32 res_trk_get_firmware_addr(struct ddl_buf_addr *firm_addr);
u32 res_trk_get_mem_type(void);
u32 res_trk_get_enable_ion(void);
+u32 res_trk_get_disable_fullhd(void);
struct ion_client *res_trk_get_ion_client(void);
u32 res_trk_get_disable_dmx(void);
void res_trk_set_mem_type(enum ddl_mem_area mem_type);
diff --git a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
index 0172427..ee76ff1 100644
--- a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.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
@@ -723,3 +723,8 @@
{
return;
}
+
+u32 res_trk_get_disable_fullhd(void)
+{
+ return 0;
+}
diff --git a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker_api.h b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker_api.h
index fbc91e2..34f2103 100644
--- a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker_api.h
+++ b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker_api.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
@@ -28,6 +28,7 @@
u32 res_trk_download_firmware(void);
u32 res_trk_get_core_type(void);
u32 res_trk_get_mem_type(void);
+u32 res_trk_get_disable_fullhd(void);
u32 res_trk_get_enable_ion(void);
struct ion_client *res_trk_get_ion_client(void);
void res_trk_set_mem_type(enum ddl_mem_area mem_type);
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 77affcd..bb3e652 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.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
@@ -2812,7 +2812,12 @@
u32 rc;
u32 frm_p_units;
(void)frm_size;
-
+ if (res_trk_get_disable_fullhd() && frm_size &&
+ (frm_size->width * frm_size->height > 1280 * 720)) {
+ VCD_MSG_ERROR("Frame size = %dX%d greater than 1280X720 not"
+ "supported", frm_size->width, frm_size->height);
+ return VCD_ERR_FAIL;
+ }
prop_hdr.prop_id = DDL_I_FRAME_PROC_UNITS;
prop_hdr.sz = sizeof(frm_p_units);
rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr, &frm_p_units);
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 8d0ca45..97f1ca7 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -134,7 +134,6 @@
extern void get_online_cpus(void);
extern void put_online_cpus(void);
-extern bool cpu_hotplug_inprogress(void);
#define hotcpu_notifier(fn, pri) cpu_notifier(fn, pri)
#define register_hotcpu_notifier(nb) register_cpu_notifier(nb)
#define unregister_hotcpu_notifier(nb) unregister_cpu_notifier(nb)
diff --git a/kernel/cpu.c b/kernel/cpu.c
index ad7eaf2..4047707 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -123,14 +123,6 @@
mutex_unlock(&cpu_hotplug.lock);
}
-bool cpu_hotplug_inprogress(void)
-{
- if (cpu_hotplug.active_writer)
- return true;
-
- return false;
-}
-
#else /* #if CONFIG_HOTPLUG_CPU */
static void cpu_hotplug_begin(void) {}
static void cpu_hotplug_done(void) {}
diff --git a/kernel/printk.c b/kernel/printk.c
index b790764..dbaa948 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -813,11 +813,6 @@
*/
static inline int can_use_console(unsigned int cpu)
{
-#ifdef CONFIG_HOTPLUG_CPU
- if (!cpu_active(cpu) && cpu_hotplug_inprogress())
- return 0;
-#endif
-
return cpu_online(cpu) || have_callable_console();
}
diff --git a/kernel/sched.c b/kernel/sched.c
index 232c1c0..b85f675 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -7653,7 +7653,6 @@
{
int i, j, n;
int new_topology;
- cpumask_var_t doms_temp;
mutex_lock(&sched_domains_mutex);
@@ -7663,20 +7662,14 @@
/* Let architecture update cpu core mappings. */
new_topology = arch_update_cpu_topology();
- cpumask_andnot(doms_temp, cpu_active_mask, cpu_isolated_map);
-
n = doms_new ? ndoms_new : 0;
/* Destroy deleted domains */
for (i = 0; i < ndoms_cur; i++) {
- if (!new_topology) {
- if ((n == 0) && cpumask_subset(doms_cur[i], doms_temp))
+ for (j = 0; j < n && !new_topology; j++) {
+ if (cpumask_equal(doms_cur[i], doms_new[j])
+ && dattrs_equal(dattr_cur, i, dattr_new, j))
goto match1;
- for (j = 0; j < n; j++) {
- if (cpumask_equal(doms_cur[i], doms_new[j])
- && dattrs_equal(dattr_cur, i, dattr_new, j))
- goto match1;
- }
}
/* no match - a current sched domain not in new doms_new[] */
detach_destroy_domains(doms_cur[i]);
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 33afdc9..deef8ac 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -48,6 +48,11 @@
#define TABLA_OCP_ATTEMPT 1
+#define TABLA_MCLK_RATE_12288KHZ 12288000
+#define TABLA_MCLK_RATE_9600KHZ 9600000
+
+#define TABLA_FAKE_INS_THRESHOLD_MS 2500
+
static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
@@ -93,8 +98,31 @@
TABLA_HPHR_DAC_OFF_ACK
};
+/* Data used by MBHC */
+struct mbhc_internal_cal_data {
+ u16 dce_z;
+ u16 dce_mb;
+ u16 sta_z;
+ u16 sta_mb;
+ u32 t_dce;
+ u32 t_sta;
+ u32 micb_mv;
+ u16 v_ins_hu;
+ u16 v_ins_h;
+ u16 v_b1_hu;
+ u16 v_b1_h;
+ u16 v_b1_huc;
+ u16 v_brh;
+ u16 v_brl;
+ u16 v_no_mic;
+ u8 nready;
+ u8 npoll;
+ u8 nbounce_wait;
+};
+
struct tabla_priv {
struct snd_soc_codec *codec;
+ u32 mclk_freq;
u32 adc_count;
u32 cfilt1_cnt;
u32 cfilt2_cnt;
@@ -105,10 +133,20 @@
bool clock_active;
bool config_mode_active;
bool mbhc_polling_active;
- bool fake_insert_context;
+ unsigned long mbhc_fake_ins_start;
int buttons_pressed;
- struct tabla_mbhc_calibration *calibration;
+ enum tabla_micbias_num micbias;
+ /* void* calibration contains:
+ * struct tabla_mbhc_general_cfg generic;
+ * struct tabla_mbhc_plug_detect_cfg plug_det;
+ * struct tabla_mbhc_plug_type_cfg plug_type;
+ * struct tabla_mbhc_btn_detect_cfg btn_det;
+ * struct tabla_mbhc_imped_detect_cfg imped_det;
+ * Note: various size depends on btn_det->num_btn
+ */
+ void *calibration;
+ struct mbhc_internal_cal_data mbhc_data;
struct snd_soc_jack *headset_jack;
struct snd_soc_jack *button_jack;
@@ -145,6 +183,9 @@
u8 hphlocp_cnt; /* headphone left ocp retry */
u8 hphrocp_cnt; /* headphone right ocp retry */
+
+ /* Callback function to enable MCLK */
+ int (*mclk_cb) (struct snd_soc_codec*, int);
};
#ifdef CONFIG_DEBUG_FS
@@ -1409,7 +1450,7 @@
if (tabla->mbhc_polling_active) {
tabla_codec_pause_hs_polling(codec);
- /* Enable Mic Bias switch to VDDIO */
+ /* VDDIO switch enabled */
tabla->cfilt_k_value = snd_soc_read(codec,
tabla->mbhc_bias_regs.cfilt_val);
cfilt_k_val = tabla_find_k_value(
@@ -1425,8 +1466,7 @@
tabla_codec_start_hs_polling(codec);
tabla->mbhc_micbias_switched = true;
- pr_debug("%s: Enabled MBHC Mic bias to VDDIO Switch\n",
- __func__);
+ pr_debug("%s: VDDIO switch enabled\n", __func__);
}
break;
@@ -1436,7 +1476,7 @@
tabla_codec_pause_hs_polling(codec);
mbhc_was_polling = true;
}
- /* Disable Mic Bias switch to VDDIO */
+ /* VDDIO switch disabled */
if (tabla->cfilt_k_value != 0)
snd_soc_update_bits(codec,
tabla->mbhc_bias_regs.cfilt_val, 0XFC,
@@ -1450,8 +1490,7 @@
tabla_codec_start_hs_polling(codec);
tabla->mbhc_micbias_switched = false;
- pr_debug("%s: Disabled MBHC Mic bias to VDDIO Switch\n",
- __func__);
+ pr_debug("%s: VDDIO switch disabled\n", __func__);
}
break;
}
@@ -1516,7 +1555,7 @@
break;
case SND_SOC_DAPM_POST_PMU:
if (tabla->mbhc_polling_active &&
- (tabla->calibration->bias == micb_line)) {
+ tabla->micbias == micb_line) {
tabla_codec_pause_hs_polling(codec);
tabla_codec_start_hs_polling(codec);
}
@@ -1673,10 +1712,8 @@
tabla_snd_soc_jack_report(tabla, tabla->headset_jack,
tabla->hph_status,
TABLA_JACK_MASK);
- snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
- 0x00);
- snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
- 0x10);
+ snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x00);
+ snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
/* reset retry counter as PA is turned off signifying
* start of new OCP detection session
*/
@@ -1761,10 +1798,9 @@
struct mbhc_micbias_regs *micbias_regs)
{
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
- struct tabla_mbhc_calibration *calibration = tabla->calibration;
unsigned int cfilt;
- switch (calibration->bias) {
+ switch (tabla->micbias) {
case TABLA_MICBIAS1:
cfilt = tabla->pdata->micbias.bias1_cfilt_sel;
micbias_regs->mbhc_reg = TABLA_A_MICB_1_MBHC;
@@ -1801,14 +1837,17 @@
case TABLA_CFILT1_SEL:
micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_1_VAL;
micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_1_CTL;
+ tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt1_mv;
break;
case TABLA_CFILT2_SEL:
micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_2_VAL;
micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_2_CTL;
+ tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt2_mv;
break;
case TABLA_CFILT3_SEL:
micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_3_VAL;
micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_3_CTL;
+ tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt3_mv;
break;
}
}
@@ -2612,24 +2651,46 @@
static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
{
- /* TODO store register values in calibration */
- snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL, 0x20);
- snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL, 0xFF);
+ u8 *n_cic;
+ struct tabla_mbhc_btn_detect_cfg *btn_det;
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
- snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL, 0xFF);
- snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL, 0x20);
+ btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
- snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0xF8);
- snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0xEE);
- snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL, 0xFC);
- snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL, 0xCE);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
+ tabla->mbhc_data.v_ins_hu & 0xFF);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
+ (tabla->mbhc_data.v_ins_hu >> 8) & 0xFF);
- snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 3);
- snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL, 9);
- snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL, 30);
- snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 120);
- snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 0x78, 0x58);
- snd_soc_write(codec, TABLA_A_CDC_MBHC_B2_CTL, 11);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
+ tabla->mbhc_data.v_b1_hu & 0xFF);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
+ (tabla->mbhc_data.v_b1_hu >> 8) & 0xFF);
+
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
+ tabla->mbhc_data.v_b1_h & 0xFF);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
+ (tabla->mbhc_data.v_b1_h >> 8) & 0xFF);
+
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL,
+ tabla->mbhc_data.v_brh & 0xFF);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL,
+ (tabla->mbhc_data.v_brh >> 8) & 0xFF);
+
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B11_CTL,
+ tabla->mbhc_data.v_brl & 0xFF);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B12_CTL,
+ (tabla->mbhc_data.v_brl >> 8) & 0xFF);
+
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL,
+ tabla->mbhc_data.nready);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL,
+ tabla->mbhc_data.npoll);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL,
+ tabla->mbhc_data.nbounce_wait);
+
+ n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, n_cic[0]);
}
static int tabla_startup(struct snd_pcm_substream *substream,
@@ -2956,42 +3017,47 @@
return bias_value;
}
-static short tabla_codec_measure_micbias_voltage(struct snd_soc_codec *codec,
- int dce)
+static short tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce)
{
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
short bias_value;
+ /* Turn on the override */
+ snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
if (dce) {
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
- usleep_range(60000, 60000);
+ usleep_range(tabla->mbhc_data.t_dce,
+ tabla->mbhc_data.t_dce);
bias_value = tabla_codec_read_dce_result(codec);
} else {
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
- usleep_range(5000, 5000);
- snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
usleep_range(50, 50);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
+ usleep_range(tabla->mbhc_data.t_sta,
+ tabla->mbhc_data.t_sta);
bias_value = tabla_codec_read_sta_result(codec);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
}
+ /* Turn off the override after measuring mic voltage */
+ snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
- pr_debug("read microphone bias value %x\n", bias_value);
+ pr_debug("read microphone bias value %04x\n", bias_value);
return bias_value;
}
static short tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
{
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
- struct tabla_mbhc_calibration *calibration = tabla->calibration;
short bias_value;
u8 cfilt_mode;
- if (!calibration) {
+ if (!tabla->calibration) {
pr_err("Error, no tabla calibration\n");
return -ENODEV;
}
@@ -3009,13 +3075,10 @@
snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
/* Make sure CFILT is in fast mode, save current mode */
- cfilt_mode = snd_soc_read(codec,
- tabla->mbhc_bias_regs.cfilt_ctl);
- snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
- 0x70, 0x00);
+ cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
+ snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
- snd_soc_update_bits(codec,
- tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
+ snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
@@ -3028,14 +3091,14 @@
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
- snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x6);
+ snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
tabla_codec_calibrate_hs_polling(codec);
- bias_value = tabla_codec_measure_micbias_voltage(codec, 0);
- snd_soc_update_bits(codec,
- tabla->mbhc_bias_regs.cfilt_ctl, 0x40, cfilt_mode);
+ bias_value = tabla_codec_sta_dce(codec, 0);
+ snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
+ cfilt_mode);
snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
return bias_value;
@@ -3045,11 +3108,14 @@
int insertion)
{
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
- struct tabla_mbhc_calibration *calibration = tabla->calibration;
int central_bias_enabled = 0;
+ const struct tabla_mbhc_general_cfg *generic =
+ TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
+ const struct tabla_mbhc_plug_detect_cfg *plug_det =
+ TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->calibration);
u8 wg_time;
- if (!calibration) {
+ if (!tabla->calibration) {
pr_err("Error, no tabla calibration\n");
return -EINVAL;
}
@@ -3070,7 +3136,7 @@
/* Enable HPH Schmitt Trigger */
snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11, 0x11);
snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
- calibration->hph_current << 2);
+ plug_det->hph_current << 2);
/* Turn off HPH PAs and DAC's during insertion detection to
* avoid false insertion interrupts
@@ -3079,9 +3145,9 @@
tabla_codec_switch_micbias(codec, 0);
snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
- 0xC0, 0x00);
+ 0xC0, 0x00);
snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
- 0xC0, 0x00);
+ 0xC0, 0x00);
usleep_range(wg_time * 1000, wg_time * 1000);
/* setup for insetion detection */
@@ -3093,10 +3159,10 @@
/* enable the mic line schmitt trigger */
snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x60,
- calibration->mic_current << 5);
+ plug_det->mic_current << 5);
snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
0x80, 0x80);
- usleep_range(calibration->mic_pid, calibration->mic_pid);
+ usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
0x10, 0x10);
@@ -3109,8 +3175,8 @@
tabla_codec_enable_config_mode(codec, 1);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
0x06, 0);
- usleep_range(calibration->shutdown_plug_removal,
- calibration->shutdown_plug_removal);
+ usleep_range(generic->t_shutdown_plug_rem,
+ generic->t_shutdown_plug_rem);
tabla_codec_enable_config_mode(codec, 0);
} else
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
@@ -3122,8 +3188,8 @@
/* If central bandgap disabled */
if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
- usleep_range(calibration->bg_fast_settle,
- calibration->bg_fast_settle);
+ usleep_range(generic->t_bg_fast_settle,
+ generic->t_bg_fast_settle);
central_bias_enabled = 1;
}
@@ -3131,14 +3197,14 @@
if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
- usleep_range(calibration->tldoh, calibration->tldoh);
+ usleep_range(generic->t_ldoh, generic->t_ldoh);
snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
if (central_bias_enabled)
snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
}
- snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x3, calibration->bias);
+ snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x3, tabla->micbias);
tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
@@ -3163,10 +3229,60 @@
wake_up(&tabla->pm_wq);
}
+static u16 tabla_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
+ s16 vin_mv)
+{
+ short diff, zero;
+ struct tabla_priv *tabla;
+ u32 mb_mv, in;
+
+ tabla = snd_soc_codec_get_drvdata(codec);
+ mb_mv = tabla->mbhc_data.micb_mv;
+
+ if (mb_mv == 0) {
+ pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
+ return -EINVAL;
+ }
+
+ if (dce) {
+ diff = tabla->mbhc_data.dce_mb - tabla->mbhc_data.dce_z;
+ zero = tabla->mbhc_data.dce_z;
+ } else {
+ diff = tabla->mbhc_data.sta_mb - tabla->mbhc_data.sta_z;
+ zero = tabla->mbhc_data.sta_z;
+ }
+ in = (u32) diff * vin_mv;
+
+ return (u16) (in / mb_mv) + zero;
+}
+
+static s32 tabla_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
+ u16 bias_value)
+{
+ struct tabla_priv *tabla;
+ s32 mv;
+
+ tabla = snd_soc_codec_get_drvdata(codec);
+
+ if (dce) {
+ mv = ((s32)bias_value - (s32)tabla->mbhc_data.dce_z) *
+ (s32)tabla->mbhc_data.micb_mv /
+ (s32)(tabla->mbhc_data.dce_mb - tabla->mbhc_data.dce_z);
+ } else {
+ mv = ((s32)bias_value - (s32)tabla->mbhc_data.sta_z) *
+ (s32)tabla->mbhc_data.micb_mv /
+ (s32)(tabla->mbhc_data.sta_mb - tabla->mbhc_data.sta_z);
+ }
+
+ return mv;
+}
+
static void btn0_lpress_fn(struct work_struct *work)
{
struct delayed_work *delayed_work;
struct tabla_priv *tabla;
+ short bias_value;
+ int dce_mv, sta_mv;
pr_debug("%s:\n", __func__);
@@ -3175,8 +3291,15 @@
if (tabla) {
if (tabla->button_jack) {
- pr_debug("%s: Reporting long button press event\n",
- __func__);
+ bias_value = tabla_codec_read_sta_result(tabla->codec);
+ sta_mv = tabla_codec_sta_dce_v(tabla->codec, 0,
+ bias_value);
+ bias_value = tabla_codec_read_dce_result(tabla->codec);
+ dce_mv = tabla_codec_sta_dce_v(tabla->codec, 1,
+ bias_value);
+ pr_debug("%s: Reporting long button press event"
+ " STA: %d, DCE: %d\n", __func__,
+ sta_mv, dce_mv);
tabla_snd_soc_jack_report(tabla, tabla->button_jack,
SND_JACK_BTN_0,
SND_JACK_BTN_0);
@@ -3188,9 +3311,246 @@
tabla_unlock_sleep(tabla);
}
+void tabla_mbhc_cal(struct snd_soc_codec *codec)
+{
+ struct tabla_priv *tabla;
+ struct tabla_mbhc_btn_detect_cfg *btn_det;
+ u8 cfilt_mode, bg_mode;
+ u8 ncic, nmeas, navg;
+ u32 mclk_rate;
+ u32 dce_wait, sta_wait;
+ u8 *n_cic;
+
+ tabla = snd_soc_codec_get_drvdata(codec);
+
+ /* First compute the DCE / STA wait times
+ * depending on tunable parameters.
+ * The value is computed in microseconds
+ */
+ btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
+ n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
+ ncic = n_cic[0];
+ nmeas = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration)->n_meas;
+ navg = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration)->mbhc_navg;
+ mclk_rate = tabla->mclk_freq;
+ dce_wait = (1000 * 512 * ncic * nmeas) / (mclk_rate / 1000);
+ if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ)
+ dce_wait = dce_wait + 10000;
+ else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ)
+ dce_wait = dce_wait + 9810;
+ else
+ WARN(1, "Unsupported mclk freq %d\n", tabla->mclk_freq);
+
+ sta_wait = (1000 * 128 * navg) / (mclk_rate / 1000);
+
+ /* Add 10 microseconds to handle error margin */
+ dce_wait = dce_wait + 10;
+ sta_wait = sta_wait + 10;
+
+ tabla->mbhc_data.t_dce = dce_wait;
+ tabla->mbhc_data.t_sta = sta_wait;
+
+ /* LDOH and CFILT are already configured during pdata handling.
+ * Only need to make sure CFILT and bandgap are in Fast mode.
+ * Need to restore defaults once calculation is done.
+ */
+ cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
+ snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
+ bg_mode = snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02,
+ 0x02);
+
+ /* Micbias, CFILT, LDOH, MBHC MUX mode settings
+ * to perform ADC calibration
+ */
+ snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x60,
+ tabla->micbias << 5);
+ snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
+ snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x60, 0x60);
+ snd_soc_write(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x78);
+ snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
+
+ /* DCE measurement for 0 volts */
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
+ snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
+ usleep_range(100, 100);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
+ usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
+ tabla->mbhc_data.dce_z = tabla_codec_read_dce_result(codec);
+
+ /* DCE measurment for MB voltage */
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
+ snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
+ usleep_range(100, 100);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
+ usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
+ tabla->mbhc_data.dce_mb = tabla_codec_read_dce_result(codec);
+
+ /* Sta measuremnt for 0 volts */
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
+ snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
+ usleep_range(100, 100);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
+ usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
+ tabla->mbhc_data.sta_z = tabla_codec_read_sta_result(codec);
+
+ /* STA Measurement for MB Voltage */
+ snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
+ usleep_range(100, 100);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
+ usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
+ tabla->mbhc_data.sta_mb = tabla_codec_read_sta_result(codec);
+
+ /* Restore default settings. */
+ snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
+ snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
+ cfilt_mode);
+ snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
+
+ snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
+ usleep_range(100, 100);
+}
+
+void *tabla_mbhc_cal_btn_det_mp(const struct tabla_mbhc_btn_detect_cfg* btn_det,
+ const enum tabla_mbhc_btn_det_mem mem)
+{
+ void *ret = &btn_det->_v_btn_low;
+
+ switch (mem) {
+ case TABLA_BTN_DET_GAIN:
+ ret += sizeof(btn_det->_n_cic);
+ case TABLA_BTN_DET_N_CIC:
+ ret += sizeof(btn_det->_n_ready);
+ case TABLA_BTN_DET_V_N_READY:
+ ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
+ case TABLA_BTN_DET_V_BTN_HIGH:
+ ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
+ case TABLA_BTN_DET_V_BTN_LOW:
+ /* do nothing */
+ break;
+ default:
+ ret = NULL;
+ }
+
+ return ret;
+}
+
+static void tabla_mbhc_calc_thres(struct snd_soc_codec *codec)
+{
+ struct tabla_priv *tabla;
+ s16 btn_mv = 0, btn_delta_mv;
+ struct tabla_mbhc_btn_detect_cfg *btn_det;
+ struct tabla_mbhc_plug_type_cfg *plug_type;
+ u16 *btn_high;
+ int i;
+
+ tabla = snd_soc_codec_get_drvdata(codec);
+ btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
+ plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->calibration);
+
+ if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ) {
+ tabla->mbhc_data.nready = 3;
+ tabla->mbhc_data.npoll = 9;
+ tabla->mbhc_data.nbounce_wait = 30;
+ } else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ) {
+ tabla->mbhc_data.nready = 2;
+ tabla->mbhc_data.npoll = 7;
+ tabla->mbhc_data.nbounce_wait = 23;
+ }
+
+ tabla->mbhc_data.v_ins_hu =
+ tabla_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
+ tabla->mbhc_data.v_ins_h =
+ tabla_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
+
+ btn_high = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_HIGH);
+ for (i = 0; i < btn_det->num_btn; i++)
+ btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
+
+ tabla->mbhc_data.v_b1_h = tabla_codec_v_sta_dce(codec, DCE, btn_mv);
+ btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
+
+ tabla->mbhc_data.v_b1_hu =
+ tabla_codec_v_sta_dce(codec, STA, btn_delta_mv);
+
+ btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
+
+ tabla->mbhc_data.v_b1_huc =
+ tabla_codec_v_sta_dce(codec, DCE, btn_delta_mv);
+
+ tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
+ tabla->mbhc_data.v_brl = 0xFA55;
+
+ tabla->mbhc_data.v_no_mic =
+ tabla_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
+}
+
+void tabla_mbhc_init(struct snd_soc_codec *codec)
+{
+ struct tabla_priv *tabla;
+ struct tabla_mbhc_general_cfg *generic;
+ struct tabla_mbhc_btn_detect_cfg *btn_det;
+ int n;
+ u8 tabla_ver;
+ u8 *n_cic, *gain;
+
+ tabla = snd_soc_codec_get_drvdata(codec);
+ generic = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
+ btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
+
+ tabla_ver = snd_soc_read(codec, TABLA_A_CHIP_VERSION);
+ tabla_ver &= 0x1F;
+
+ for (n = 0; n < 8; n++) {
+ if ((tabla_ver != TABLA_VERSION_1_0 &&
+ tabla_ver != TABLA_VERSION_1_1) || n != 7) {
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_MBHC_FEATURE_B1_CFG,
+ 0x07, n);
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_FEATURE_B2_CFG,
+ btn_det->c[n]);
+ }
+ }
+ snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x07,
+ btn_det->nc);
+
+ n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
+ snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
+ n_cic[0]);
+
+ gain = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_GAIN);
+ snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x78, gain[0] << 3);
+
+ snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
+ generic->mbhc_nsa << 4);
+
+ snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
+ btn_det->n_meas);
+
+ snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
+
+ snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
+
+ snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x78,
+ btn_det->mbhc_nsc << 3);
+
+ snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x03, TABLA_MICBIAS2);
+
+ snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
+}
+
int tabla_hs_detect(struct snd_soc_codec *codec,
- struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
- struct tabla_mbhc_calibration *calibration)
+ struct snd_soc_jack *headset_jack,
+ struct snd_soc_jack *button_jack,
+ void *calibration, enum tabla_micbias_num micbias,
+ int (*mclk_cb_fn) (struct snd_soc_codec*, int),
+ int read_fw_bin, u32 mclk_rate)
{
struct tabla_priv *tabla;
int rc;
@@ -3202,7 +3562,10 @@
tabla = snd_soc_codec_get_drvdata(codec);
tabla->headset_jack = headset_jack;
tabla->button_jack = button_jack;
+ tabla->micbias = micbias;
tabla->calibration = calibration;
+ tabla->mclk_cb = mclk_cb_fn;
+ tabla->mclk_freq = mclk_rate;
tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
/* Put CFILT in fast mode by default */
@@ -3212,7 +3575,19 @@
INIT_DELAYED_WORK(&tabla->btn0_dwork, btn0_lpress_fn);
INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
- rc = tabla_codec_enable_hs_detect(codec, 1);
+
+ if (!read_fw_bin) {
+ tabla->mclk_cb(codec, 1);
+ tabla_mbhc_init(codec);
+ tabla_mbhc_cal(codec);
+ tabla_mbhc_calc_thres(codec);
+ tabla->mclk_cb(codec, 0);
+ tabla_codec_calibrate_hs_polling(codec);
+ rc = tabla_codec_enable_hs_detect(codec, 1);
+ } else {
+ pr_err("%s: MBHC firmware read not supported\n", __func__);
+ rc = -EINVAL;
+ }
if (!IS_ERR_VALUE(rc)) {
snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
@@ -3238,12 +3613,14 @@
tabla_lock_sleep(priv);
bias_value = tabla_codec_read_dce_result(codec);
- pr_debug("%s: button press interrupt, bias value(DCE Read)=%d\n",
- __func__, bias_value);
+ pr_debug("%s: button press interrupt, DCE: %d,%d\n",
+ __func__, bias_value,
+ tabla_codec_sta_dce_v(codec, 1, bias_value));
bias_value = tabla_codec_read_sta_result(codec);
- pr_debug("%s: button press interrupt, bias value(STA Read)=%d\n",
- __func__, bias_value);
+ pr_debug("%s: button press interrupt, STA: %d,%d\n",
+ __func__, bias_value,
+ tabla_codec_sta_dce_v(codec, 0, bias_value));
/*
* TODO: If button pressed is not button 0,
* report the button press event immediately.
@@ -3265,54 +3642,44 @@
{
struct tabla_priv *priv = data;
struct snd_soc_codec *codec = priv->codec;
- int ret, mic_voltage;
+ int ret, mb_v;
pr_debug("%s\n", __func__);
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
tabla_lock_sleep(priv);
- mic_voltage = tabla_codec_read_dce_result(codec);
- pr_debug("%s: Microphone Voltage on release(DCE Read) = %d\n",
- __func__, mic_voltage);
-
if (priv->buttons_pressed & SND_JACK_BTN_0) {
ret = cancel_delayed_work(&priv->btn0_dwork);
if (ret == 0) {
-
pr_debug("%s: Reporting long button release event\n",
__func__);
- if (priv->button_jack) {
+ if (priv->button_jack)
tabla_snd_soc_jack_report(priv,
priv->button_jack, 0,
SND_JACK_BTN_0);
- }
-
} else {
/* if scheduled btn0_dwork is canceled from here,
* we have to unlock from here instead btn0_work */
tabla_unlock_sleep(priv);
- mic_voltage =
- tabla_codec_measure_micbias_voltage(codec, 0);
- pr_debug("%s: Mic Voltage on release(new STA) = %d\n",
- __func__, mic_voltage);
+ mb_v = tabla_codec_sta_dce(codec, 0);
+ pr_debug("%s: Mic Voltage on release STA: %d,%d\n",
+ __func__, mb_v,
+ tabla_codec_sta_dce_v(codec, 0, mb_v));
- if (mic_voltage < -2000 || mic_voltage > -670) {
+ if (mb_v < -2000 || mb_v > -670)
pr_debug("%s: Fake buttton press interrupt\n",
__func__);
- } else {
-
- if (priv->button_jack) {
- pr_debug("%s:reporting short button press and release\n",
- __func__);
-
- tabla_snd_soc_jack_report(priv,
- priv->button_jack,
- SND_JACK_BTN_0, SND_JACK_BTN_0);
- tabla_snd_soc_jack_report(priv,
- priv->button_jack,
- 0, SND_JACK_BTN_0);
- }
+ else if (priv->button_jack) {
+ pr_debug("%s:reporting short button "
+ "press and release\n", __func__);
+ tabla_snd_soc_jack_report(priv,
+ priv->button_jack,
+ SND_JACK_BTN_0,
+ SND_JACK_BTN_0);
+ tabla_snd_soc_jack_report(priv,
+ priv->button_jack,
+ 0, SND_JACK_BTN_0);
}
}
@@ -3327,7 +3694,8 @@
static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
{
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
- struct tabla_mbhc_calibration *calibration = tabla->calibration;
+ const struct tabla_mbhc_general_cfg *generic =
+ TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
tabla_codec_enable_config_mode(codec, 1);
@@ -3335,10 +3703,10 @@
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
- snd_soc_update_bits(codec,
- tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
- usleep_range(calibration->shutdown_plug_removal,
- calibration->shutdown_plug_removal);
+ snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
+
+ usleep_range(generic->t_shutdown_plug_rem,
+ generic->t_shutdown_plug_rem);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
@@ -3461,13 +3829,14 @@
{
struct tabla_priv *priv = data;
struct snd_soc_codec *codec = priv->codec;
+ const struct tabla_mbhc_plug_detect_cfg *plug_det =
+ TABLA_MBHC_CAL_PLUG_DET_PTR(priv->calibration);
int ldo_h_on, micb_cfilt_on;
- short mic_voltage;
- short threshold_no_mic = 0xF7F6;
- short threshold_fake_insert = 0xFD30;
+ short mb_v;
u8 is_removal;
+ int mic_mv;
- pr_debug("%s\n", __func__);
+ pr_debug("%s: enter\n", __func__);
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
tabla_lock_sleep(priv);
@@ -3475,38 +3844,40 @@
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
/* Turn off both HPH and MIC line schmitt triggers */
- snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
- 0x90, 0x00);
+ snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
- if (priv->fake_insert_context) {
+ if (priv->mbhc_fake_ins_start &&
+ time_after(jiffies, priv->mbhc_fake_ins_start +
+ msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
pr_debug("%s: fake context interrupt, reset insertion\n",
- __func__);
- priv->fake_insert_context = false;
+ __func__);
+ priv->mbhc_fake_ins_start = 0;
tabla_codec_shutdown_hs_polling(codec);
tabla_codec_enable_hs_detect(codec, 1);
return IRQ_HANDLED;
}
-
ldo_h_on = snd_soc_read(codec, TABLA_A_LDO_H_MODE_1) & 0x80;
- micb_cfilt_on = snd_soc_read(codec,
- priv->mbhc_bias_regs.cfilt_ctl) & 0x80;
+ micb_cfilt_on = snd_soc_read(codec, priv->mbhc_bias_regs.cfilt_ctl)
+ & 0x80;
if (!ldo_h_on)
snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x80);
if (!micb_cfilt_on)
snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
- 0x80, 0x80);
-
- usleep_range(priv->calibration->setup_plug_removal_delay,
- priv->calibration->setup_plug_removal_delay);
+ 0x80, 0x80);
+ if (plug_det->t_ins_complete > 20)
+ msleep(plug_det->t_ins_complete);
+ else
+ usleep_range(plug_det->t_ins_complete * 1000,
+ plug_det->t_ins_complete * 1000);
if (!ldo_h_on)
snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x0);
if (!micb_cfilt_on)
snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
- 0x80, 0x0);
+ 0x80, 0x0);
if (is_removal) {
/*
@@ -3543,37 +3914,56 @@
return IRQ_HANDLED;
}
- mic_voltage = tabla_codec_setup_hs_polling(codec);
+ mb_v = tabla_codec_setup_hs_polling(codec);
+ mic_mv = tabla_codec_sta_dce_v(codec, 0, mb_v);
- if (mic_voltage > threshold_fake_insert) {
- pr_debug("%s: Fake insertion interrupt, mic_voltage = %x\n",
- __func__, mic_voltage);
-
- /* Disable HPH trigger and enable MIC line trigger */
- snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
-
- snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x60,
- priv->calibration->mic_current << 5);
- snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
- 0x80, 0x80);
- usleep_range(priv->calibration->mic_pid,
- priv->calibration->mic_pid);
- snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
- 0x10, 0x10);
-
+ if (mb_v > (short) priv->mbhc_data.v_ins_hu) {
+ pr_debug("%s: Fake insertion interrupt since %dmsec ago, "
+ "STA : %d,%d\n", __func__,
+ (priv->mbhc_fake_ins_start ?
+ jiffies_to_msecs(jiffies -
+ priv->mbhc_fake_ins_start) :
+ 0),
+ mb_v, mic_mv);
+ if (time_after(jiffies,
+ priv->mbhc_fake_ins_start +
+ msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
+ /* Disable HPH trigger and enable MIC line trigger */
+ snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12,
+ 0x00);
+ snd_soc_update_bits(codec,
+ priv->mbhc_bias_regs.mbhc_reg, 0x60,
+ plug_det->mic_current << 5);
+ snd_soc_update_bits(codec,
+ priv->mbhc_bias_regs.mbhc_reg,
+ 0x80, 0x80);
+ usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
+ snd_soc_update_bits(codec,
+ priv->mbhc_bias_regs.mbhc_reg,
+ 0x10, 0x10);
+ } else {
+ if (priv->mbhc_fake_ins_start == 0)
+ priv->mbhc_fake_ins_start = jiffies;
+ /* Setup normal insert detection
+ * Enable HPH Schmitt Trigger
+ */
+ snd_soc_update_bits(codec, TABLA_A_MBHC_HPH,
+ 0x13 | 0x0C,
+ 0x13 | plug_det->hph_current << 2);
+ }
/* Setup for insertion detection */
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
- priv->fake_insert_context = true;
tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
- } else if (mic_voltage < threshold_no_mic) {
- pr_debug("%s: Headphone Detected, mic_voltage = %x\n",
- __func__, mic_voltage);
+ } else if (mb_v < (short) priv->mbhc_data.v_no_mic) {
+ pr_debug("%s: Headphone Detected, mb_v: %d,%d\n",
+ __func__, mb_v, mic_mv);
+ priv->mbhc_fake_ins_start = 0;
priv->hph_status |= SND_JACK_HEADPHONE;
if (priv->headset_jack) {
pr_debug("%s: Reporting insertion %d\n", __func__,
- SND_JACK_HEADPHONE);
+ SND_JACK_HEADPHONE);
tabla_snd_soc_jack_report(priv, priv->headset_jack,
priv->hph_status,
TABLA_JACK_MASK);
@@ -3582,16 +3972,19 @@
tabla_codec_enable_hs_detect(codec, 0);
tabla_sync_hph_state(priv);
} else {
- pr_debug("%s: Headset detected, mic_voltage = %x\n",
- __func__, mic_voltage);
+ pr_debug("%s: Headset detected, mb_v: %d,%d\n",
+ __func__, mb_v, mic_mv);
+ priv->mbhc_fake_ins_start = 0;
priv->hph_status |= SND_JACK_HEADSET;
if (priv->headset_jack) {
pr_debug("%s: Reporting insertion %d\n", __func__,
- SND_JACK_HEADSET);
+ SND_JACK_HEADSET);
tabla_snd_soc_jack_report(priv, priv->headset_jack,
priv->hph_status,
TABLA_JACK_MASK);
}
+ /* avoid false button press detect */
+ msleep(50);
tabla_codec_start_hs_polling(codec);
tabla_sync_hph_state(priv);
}
@@ -3604,6 +3997,8 @@
{
struct tabla_priv *priv = data;
struct snd_soc_codec *codec = priv->codec;
+ const struct tabla_mbhc_general_cfg *generic =
+ TABLA_MBHC_CAL_GENERAL_PTR(priv->calibration);
short bias_value;
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
@@ -3611,13 +4006,14 @@
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
tabla_lock_sleep(priv);
- usleep_range(priv->calibration->shutdown_plug_removal,
- priv->calibration->shutdown_plug_removal);
+ usleep_range(generic->t_shutdown_plug_rem,
+ generic->t_shutdown_plug_rem);
- bias_value = tabla_codec_measure_micbias_voltage(codec, 1);
- pr_debug("removal interrupt, bias value is %d\n", bias_value);
+ bias_value = tabla_codec_sta_dce(codec, 1);
+ pr_debug("removal interrupt, DCE: %d,%d\n",
+ bias_value, tabla_codec_sta_dce_v(codec, 1, bias_value));
- if (bias_value < -90) {
+ if (bias_value < (short) priv->mbhc_data.v_ins_h) {
pr_debug("False alarm, headset not actually removed\n");
tabla_codec_start_hs_polling(codec);
} else {
@@ -3940,6 +4336,11 @@
tabla->cfilt_k_value = 0;
tabla->mbhc_micbias_switched = false;
+ /* Make sure mbhc intenal calibration data is zeroed out */
+ memset(&tabla->mbhc_data, 0,
+ sizeof(struct mbhc_internal_cal_data));
+ tabla->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
+ tabla->mbhc_data.t_sta = DEFAULT_STA_WAIT;
snd_soc_codec_set_drvdata(codec, tabla);
tabla->mclk_enabled = false;
@@ -3947,7 +4348,7 @@
tabla->clock_active = false;
tabla->config_mode_active = false;
tabla->mbhc_polling_active = false;
- tabla->fake_insert_context = false;
+ tabla->mbhc_fake_ins_start = 0;
tabla->no_mic_headset_override = false;
tabla->codec = codec;
tabla->pdata = dev_get_platdata(codec->dev->parent);
@@ -3981,7 +4382,8 @@
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
tabla_version = snd_soc_read(codec, TABLA_A_CHIP_VERSION);
- pr_info("%s : Tabla version reg 0x%2x\n", __func__, (u32)tabla_version);
+ pr_info("%s : Tabla version reg 0x%2x\n", __func__,
+ (u32)tabla_version);
tabla_version &= 0x1F;
pr_info("%s : Tabla version %u\n", __func__, (u32)tabla_version);
diff --git a/sound/soc/codecs/wcd9310.h b/sound/soc/codecs/wcd9310.h
index 32fc48f..66c3e39 100644
--- a/sound/soc/codecs/wcd9310.h
+++ b/sound/soc/codecs/wcd9310.h
@@ -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
@@ -9,7 +9,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-
#include <sound/soc.h>
#define TABLA_VERSION_1_0 0
@@ -22,6 +21,13 @@
#define TABLA_REG_VAL(reg, val) {reg, 0, val}
+
+#define DEFAULT_DCE_WAIT 60000
+#define DEFAULT_STA_WAIT 5000
+
+#define STA 0
+#define DCE 1
+
extern const u8 tabla_reg_readable[TABLA_CACHE_SIZE];
extern const u8 tabla_reg_defaults[TABLA_CACHE_SIZE];
@@ -39,26 +45,116 @@
TABLA_PID_MIC_20_UA,
};
-struct tabla_mbhc_calibration {
- enum tabla_micbias_num bias;
- int tldoh;
- int bg_fast_settle;
- enum tabla_pid_current mic_current;
- int mic_pid;
- enum tabla_pid_current hph_current;
- int setup_plug_removal_delay;
- int shutdown_plug_removal;
-};
-
struct tabla_reg_mask_val {
u16 reg;
u8 mask;
u8 val;
};
+enum tabla_mbhc_clk_freq {
+ TABLA_MCLK_12P2MHZ = 0,
+ TABLA_MCLK_9P6MHZ,
+ TABLA_NUM_CLK_FREQS,
+};
+
+enum tabla_mbhc_analog_pwr_cfg {
+ TABLA_ANALOG_PWR_COLLAPSED = 0,
+ TABLA_ANALOG_PWR_ON,
+ TABLA_NUM_ANALOG_PWR_CONFIGS,
+};
+
+enum tabla_mbhc_btn_det_mem {
+ TABLA_BTN_DET_V_BTN_LOW,
+ TABLA_BTN_DET_V_BTN_HIGH,
+ TABLA_BTN_DET_V_N_READY,
+ TABLA_BTN_DET_N_CIC,
+ TABLA_BTN_DET_GAIN
+};
+
+struct tabla_mbhc_general_cfg {
+ u8 t_ldoh;
+ u8 t_bg_fast_settle;
+ u8 t_shutdown_plug_rem;
+ u8 mbhc_nsa;
+ u8 mbhc_navg;
+ u8 v_micbias_l;
+ u8 v_micbias;
+ u8 mbhc_reserved;
+ u16 settle_wait;
+ u16 t_micbias_rampup;
+ u16 t_micbias_rampdown;
+ u16 t_supply_bringup;
+} __packed;
+
+struct tabla_mbhc_plug_detect_cfg {
+ u32 mic_current;
+ u32 hph_current;
+ u16 t_mic_pid;
+ u16 t_ins_complete;
+ u16 t_ins_retry;
+ u16 v_removal_delta;
+ u8 micbias_slow_ramp;
+ u8 reserved0;
+ u8 reserved1;
+ u8 reserved2;
+} __packed;
+
+struct tabla_mbhc_plug_type_cfg {
+ u8 av_detect;
+ u8 mono_detect;
+ u8 num_ins_tries;
+ u8 reserved0;
+ s16 v_no_mic;
+ s16 v_av_min;
+ s16 v_av_max;
+ s16 v_hs_min;
+ s16 v_hs_max;
+ u16 reserved1;
+} __packed;
+
+
+struct tabla_mbhc_btn_detect_cfg {
+ s8 c[8];
+ u8 nc;
+ u8 n_meas;
+ u8 mbhc_nsc;
+ u8 n_btn_meas;
+ u8 n_btn_con;
+ u8 num_btn;
+ u8 reserved0;
+ u8 reserved1;
+ u16 t_poll;
+ u16 t_bounce_wait;
+ u16 t_rel_timeout;
+ s16 v_btn_press_delta_sta;
+ s16 v_btn_press_delta_cic;
+ u16 t_btn0_timeout;
+ s16 _v_btn_low[0]; /* v_btn_low[num_btn] */
+ s16 _v_btn_high[0]; /* v_btn_high[num_btn] */
+ u8 _n_ready[TABLA_NUM_CLK_FREQS];
+ u8 _n_cic[TABLA_NUM_CLK_FREQS];
+ u8 _gain[TABLA_NUM_CLK_FREQS];
+} __packed;
+
+struct tabla_mbhc_imped_detect_cfg {
+ u8 _hs_imped_detect;
+ u8 _n_rload;
+ u8 _hph_keep_on;
+ u8 _repeat_rload_calc;
+ u16 _t_dac_ramp_time;
+ u16 _rhph_high;
+ u16 _rhph_low;
+ u16 _rload[0]; /* rload[n_rload] */
+ u16 _alpha[0]; /* alpha[n_rload] */
+ u16 _beta[3];
+} __packed;
+
extern int tabla_hs_detect(struct snd_soc_codec *codec,
- struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
- struct tabla_mbhc_calibration *calibration);
+ struct snd_soc_jack *headset_jack,
+ struct snd_soc_jack *button_jack,
+ void *calibration, enum tabla_micbias_num micbis,
+ int (*mclk_cb_fn) (struct snd_soc_codec*, int),
+ int read_fw_bin, u32 mclk_rate);
struct anc_header {
u32 reserved[3];
@@ -66,3 +162,38 @@
};
extern int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable);
+
+extern void *tabla_mbhc_cal_btn_det_mp(const struct tabla_mbhc_btn_detect_cfg
+ *btn_det,
+ const enum tabla_mbhc_btn_det_mem mem);
+
+#define TABLA_MBHC_CAL_SIZE(buttons, rload) ( \
+ sizeof(enum tabla_micbias_num) + \
+ sizeof(struct tabla_mbhc_general_cfg) + \
+ sizeof(struct tabla_mbhc_plug_detect_cfg) + \
+ ((sizeof(s16) + sizeof(s16)) * buttons) + \
+ sizeof(struct tabla_mbhc_plug_type_cfg) + \
+ sizeof(struct tabla_mbhc_btn_detect_cfg) + \
+ sizeof(struct tabla_mbhc_imped_detect_cfg) + \
+ ((sizeof(u16) + sizeof(u16)) * rload) \
+ )
+
+#define TABLA_MBHC_CAL_GENERAL_PTR(cali) ( \
+ (struct tabla_mbhc_general_cfg *) cali)
+#define TABLA_MBHC_CAL_PLUG_DET_PTR(cali) ( \
+ (struct tabla_mbhc_plug_detect_cfg *) \
+ &(TABLA_MBHC_CAL_GENERAL_PTR(cali)[1]))
+#define TABLA_MBHC_CAL_PLUG_TYPE_PTR(cali) ( \
+ (struct tabla_mbhc_plug_type_cfg *) \
+ &(TABLA_MBHC_CAL_PLUG_DET_PTR(cali)[1]))
+#define TABLA_MBHC_CAL_BTN_DET_PTR(cali) ( \
+ (struct tabla_mbhc_btn_detect_cfg *) \
+ &(TABLA_MBHC_CAL_PLUG_TYPE_PTR(cali)[1]))
+#define TABLA_MBHC_CAL_IMPED_DET_PTR(cali) ( \
+ (struct tabla_mbhc_imped_detect_cfg *) \
+ (((void *)&TABLA_MBHC_CAL_BTN_DET_PTR(cali)[1]) + \
+ (TABLA_MBHC_CAL_BTN_DET_PTR(cali)->num_btn * \
+ (sizeof(TABLA_MBHC_CAL_BTN_DET_PTR(cali)->_v_btn_low[0]) + \
+ sizeof(TABLA_MBHC_CAL_BTN_DET_PTR(cali)->_v_btn_high[0])))) \
+ )
+
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index 870bd20..bd41e0b 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.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
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/slab.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
@@ -52,6 +53,11 @@
#define GPIO_AUX_PCM_SYNC 45
#define GPIO_AUX_PCM_CLK 46
+#define TABLA_EXT_CLK_RATE 12288000
+
+#define TABLA_MBHC_DEF_BUTTONS 3
+#define TABLA_MBHC_DEF_RLOADS 5
+
static u32 top_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(18);
static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
static int msm_spk_control;
@@ -63,17 +69,6 @@
static int msm_btsco_rate = BTSCO_RATE_8KHZ;
static int msm_btsco_ch = 1;
-struct tabla_mbhc_calibration tabla_calib = {
- .bias = TABLA_MICBIAS2,
- .tldoh = 100,
- .bg_fast_settle = 100,
- .mic_current = TABLA_PID_MIC_5_UA,
- .mic_pid = 100,
- .hph_current = TABLA_PID_MIC_5_UA,
- .setup_plug_removal_delay = 1000000,
- .shutdown_plug_removal = 100000,
-};
-
static struct clk *codec_clk;
static int clk_users;
@@ -82,6 +77,8 @@
static struct snd_soc_jack hs_jack;
static struct snd_soc_jack button_jack;
+static void *tabla_mbhc_cal;
+
static void msm_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
{
int ret = 0;
@@ -303,6 +300,42 @@
return 0;
}
+int msm_enable_codec_ext_clk(
+ struct snd_soc_codec *codec, int enable)
+{
+ pr_debug("%s: enable = %d\n", __func__, enable);
+ if (enable) {
+ clk_users++;
+ pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+ if (clk_users != 1)
+ return 0;
+
+ codec_clk = clk_get(NULL, "i2s_spkr_osr_clk");
+ if (codec_clk) {
+ clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
+ clk_enable(codec_clk);
+ tabla_mclk_enable(codec, 1);
+ } else {
+ pr_err("%s: Error setting Tabla MCLK\n", __func__);
+ clk_users--;
+ return -EINVAL;
+ }
+ } else {
+ pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+ if (clk_users == 0)
+ return 0;
+ clk_users--;
+ if (!clk_users) {
+ pr_debug("%s: disabling MCLK. clk_users = %d\n",
+ __func__, clk_users);
+ clk_disable(codec_clk);
+ clk_put(codec_clk);
+ tabla_mclk_enable(codec, 0);
+ }
+ }
+ return 0;
+}
+
static int msm_mclk_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -570,6 +603,74 @@
return 0;
}
+static void *def_tabla_mbhc_cal(void)
+{
+ void *tabla_cal;
+ struct tabla_mbhc_btn_detect_cfg *btn_cfg;
+ u16 *btn_low, *btn_high;
+ u8 *n_cic, *gain;
+
+ tabla_cal = kzalloc(TABLA_MBHC_CAL_SIZE(TABLA_MBHC_DEF_BUTTONS,
+ TABLA_MBHC_DEF_RLOADS),
+ GFP_KERNEL);
+ if (!tabla_cal) {
+ pr_err("%s: out of memory\n", __func__);
+ return NULL;
+ }
+
+#define S(X, Y) ((TABLA_MBHC_CAL_GENERAL_PTR(tabla_cal)->X) = (Y))
+ S(t_ldoh, 100);
+ S(t_bg_fast_settle, 100);
+ S(t_shutdown_plug_rem, 255);
+ S(mbhc_nsa, 4);
+ S(mbhc_navg, 4);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_DET_PTR(tabla_cal)->X) = (Y))
+ S(mic_current, TABLA_PID_MIC_5_UA);
+ S(hph_current, TABLA_PID_MIC_5_UA);
+ S(t_mic_pid, 100);
+ S(t_ins_complete, 1000);
+ S(t_ins_retry, 200);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla_cal)->X) = (Y))
+ S(v_no_mic, 30);
+ S(v_hs_max, 1450);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal)->X) = (Y))
+ S(c[0], 6);
+ S(c[1], 10);
+ S(c[2], 10);
+ S(c[3], 14);
+ S(c[4], 14);
+ S(c[5], 16);
+ S(c[6], 0);
+ S(c[7], 0);
+ S(nc, 5);
+ S(n_meas, 11);
+ S(mbhc_nsc, 11);
+ S(num_btn, TABLA_MBHC_DEF_BUTTONS);
+ S(v_btn_press_delta_sta, 100);
+ S(v_btn_press_delta_cic, 50);
+#undef S
+ btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal);
+ btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
+ btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
+ btn_low[0] = 0;
+ btn_high[0] = 40;
+ btn_low[1] = 60;
+ btn_high[1] = 140;
+ btn_low[2] = 160;
+ btn_high[2] = 240;
+ n_cic = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_CIC);
+ n_cic[0] = 120;
+ n_cic[1] = 94;
+ gain = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_GAIN);
+ gain[0] = 11;
+ gain[1] = 9;
+
+ return tabla_cal;
+}
+
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
int err;
@@ -618,7 +719,9 @@
return err;
}
- tabla_hs_detect(codec, &hs_jack, &button_jack, &tabla_calib);
+ tabla_hs_detect(codec, &hs_jack, &button_jack, tabla_mbhc_cal,
+ TABLA_MICBIAS2, msm_enable_codec_ext_clk, 0,
+ TABLA_EXT_CLK_RATE);
return 0;
}
@@ -1122,9 +1225,16 @@
return -ENODEV;
}
+ tabla_mbhc_cal = def_tabla_mbhc_cal();
+ if (!tabla_mbhc_cal) {
+ pr_err("Calibration data allocation failed\n");
+ return -ENOMEM;
+ }
+
msm_snd_device = platform_device_alloc("soc-audio", 0);
if (!msm_snd_device) {
pr_err("Platform device allocation failed\n");
+ kfree(tabla_mbhc_cal);
return -ENOMEM;
}
@@ -1132,6 +1242,7 @@
ret = platform_device_add(msm_snd_device);
if (ret) {
platform_device_put(msm_snd_device);
+ kfree(tabla_mbhc_cal);
return ret;
}
diff --git a/sound/soc/msm/msm-pcm-voice.c b/sound/soc/msm/msm-pcm-voice.c
index 5b50509..eafe0f9 100644
--- a/sound/soc/msm/msm-pcm-voice.c
+++ b/sound/soc/msm/msm-pcm-voice.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
@@ -270,8 +270,8 @@
pr_debug("%s: st enable=%d\n", __func__, st_enable);
- voc_set_slowtalk_enable(voc_get_session_id(VOICE_SESSION_NAME),
- st_enable);
+ voc_set_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
+ MODULE_ID_VOICE_MODULE_ST, st_enable);
return 0;
}
@@ -280,7 +280,30 @@
struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.integer.value[0] =
- voc_get_slowtalk_enable(voc_get_session_id(VOICE_SESSION_NAME));
+ voc_get_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
+ MODULE_ID_VOICE_MODULE_ST);
+ return 0;
+}
+
+static int msm_voice_fens_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int fens_enable = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: fens enable=%d\n", __func__, fens_enable);
+
+ voc_set_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
+ MODULE_ID_VOICE_MODULE_FENS, fens_enable);
+
+ return 0;
+}
+
+static int msm_voice_fens_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] =
+ voc_get_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
+ MODULE_ID_VOICE_MODULE_FENS);
return 0;
}
@@ -295,6 +318,8 @@
msm_voice_widevoice_get, msm_voice_widevoice_put),
SOC_SINGLE_EXT("Slowtalk Enable", SND_SOC_NOPM, 0, 1, 0,
msm_voice_slowtalk_get, msm_voice_slowtalk_put),
+ SOC_SINGLE_EXT("FENS Enable", SND_SOC_NOPM, 0, 1, 0,
+ msm_voice_fens_get, msm_voice_fens_put),
};
static struct snd_pcm_ops msm_pcm_ops = {
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index 2e98627..f26edc5 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.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
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/slab.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
@@ -52,6 +53,11 @@
#define GPIO_AUX_PCM_SYNC 65
#define GPIO_AUX_PCM_CLK 66
+#define TABLA_EXT_CLK_RATE 12288000
+
+#define TABLA_MBHC_DEF_BUTTONS 3
+#define TABLA_MBHC_DEF_RLOADS 5
+
static u32 top_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(18);
static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
static int msm8960_spk_control;
@@ -63,17 +69,6 @@
static int msm8960_btsco_rate = BTSCO_RATE_8KHZ;
static int msm8960_btsco_ch = 1;
-struct tabla_mbhc_calibration tabla_cal = {
- .bias = TABLA_MICBIAS2,
- .tldoh = 100,
- .bg_fast_settle = 100,
- .mic_current = TABLA_PID_MIC_5_UA,
- .mic_pid = 100,
- .hph_current = TABLA_PID_MIC_5_UA,
- .setup_plug_removal_delay = 1000000,
- .shutdown_plug_removal = 100000,
-};
-
static struct clk *codec_clk;
static int clk_users;
@@ -82,6 +77,8 @@
static struct snd_soc_jack hs_jack;
static struct snd_soc_jack button_jack;
+static void *tabla_mbhc_cal;
+
static void msm8960_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
{
int ret = 0;
@@ -302,6 +299,41 @@
}
return 0;
}
+int msm8960_enable_codec_ext_clk(
+ struct snd_soc_codec *codec, int enable)
+{
+ pr_debug("%s: enable = %d\n", __func__, enable);
+ if (enable) {
+ clk_users++;
+ pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+ if (clk_users != 1)
+ return 0;
+
+ codec_clk = clk_get(NULL, "i2s_spkr_osr_clk");
+ if (codec_clk) {
+ clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
+ clk_enable(codec_clk);
+ tabla_mclk_enable(codec, 1);
+ } else {
+ pr_err("%s: Error setting Tabla MCLK\n", __func__);
+ clk_users--;
+ return -EINVAL;
+ }
+ } else {
+ pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+ if (clk_users == 0)
+ return 0;
+ clk_users--;
+ if (!clk_users) {
+ pr_debug("%s: disabling MCLK. clk_users = %d\n",
+ __func__, clk_users);
+ clk_disable(codec_clk);
+ clk_put(codec_clk);
+ tabla_mclk_enable(codec, 0);
+ }
+ }
+ return 0;
+}
static int msm8960_mclk_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
@@ -310,43 +342,9 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
-
- clk_users++;
- pr_debug("%s: clk_users = %d\n", __func__, clk_users);
-
- if (clk_users != 1)
- return 0;
-
- codec_clk = clk_get(NULL, "i2s_spkr_osr_clk");
- if (codec_clk) {
- clk_set_rate(codec_clk, 12288000);
- clk_enable(codec_clk);
- tabla_mclk_enable(w->codec, 1);
-
- } else {
- pr_err("%s: Error setting Tabla MCLK\n", __func__);
- clk_users--;
- return -EINVAL;
- }
- break;
+ return msm8960_enable_codec_ext_clk(w->codec, 1);
case SND_SOC_DAPM_POST_PMD:
-
- pr_debug("%s: clk_users = %d\n", __func__, clk_users);
-
- if (clk_users == 0)
- return 0;
-
- clk_users--;
-
- if (!clk_users) {
- pr_debug("%s: disabling MCLK. clk_users = %d\n",
- __func__, clk_users);
-
- clk_disable(codec_clk);
- clk_put(codec_clk);
- tabla_mclk_enable(w->codec, 0);
- }
- break;
+ return msm8960_enable_codec_ext_clk(w->codec, 0);
}
return 0;
}
@@ -481,7 +479,7 @@
struct snd_ctl_elem_value *ucontrol)
{
pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__,
- msm8960_slim_0_rx_ch);
+ msm8960_slim_0_rx_ch);
ucontrol->value.integer.value[0] = msm8960_slim_0_rx_ch - 1;
return 0;
}
@@ -492,7 +490,7 @@
msm8960_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__,
- msm8960_slim_0_rx_ch);
+ msm8960_slim_0_rx_ch);
return 1;
}
@@ -500,7 +498,7 @@
struct snd_ctl_elem_value *ucontrol)
{
pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
- msm8960_slim_0_tx_ch);
+ msm8960_slim_0_tx_ch);
ucontrol->value.integer.value[0] = msm8960_slim_0_tx_ch - 1;
return 0;
}
@@ -511,15 +509,14 @@
msm8960_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
- msm8960_slim_0_tx_ch);
+ msm8960_slim_0_tx_ch);
return 1;
}
static int msm8960_btsco_rate_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- pr_debug("%s: msm8960_btsco_rate = %d", __func__,
- msm8960_btsco_rate);
+ pr_debug("%s: msm8960_btsco_rate = %d", __func__, msm8960_btsco_rate);
ucontrol->value.integer.value[0] = msm8960_btsco_rate;
return 0;
}
@@ -538,8 +535,7 @@
msm8960_btsco_rate = BTSCO_RATE_8KHZ;
break;
}
- pr_debug("%s: msm8960_btsco_rate = %d\n", __func__,
- msm8960_btsco_rate);
+ pr_debug("%s: msm8960_btsco_rate = %d\n", __func__, msm8960_btsco_rate);
return 0;
}
@@ -570,6 +566,74 @@
return 0;
}
+static void *def_tabla_mbhc_cal(void)
+{
+ void *tabla_cal;
+ struct tabla_mbhc_btn_detect_cfg *btn_cfg;
+ u16 *btn_low, *btn_high;
+ u8 *n_cic, *gain;
+
+ tabla_cal = kzalloc(TABLA_MBHC_CAL_SIZE(TABLA_MBHC_DEF_BUTTONS,
+ TABLA_MBHC_DEF_RLOADS),
+ GFP_KERNEL);
+ if (!tabla_cal) {
+ pr_err("%s: out of memory\n", __func__);
+ return NULL;
+ }
+
+#define S(X, Y) ((TABLA_MBHC_CAL_GENERAL_PTR(tabla_cal)->X) = (Y))
+ S(t_ldoh, 100);
+ S(t_bg_fast_settle, 100);
+ S(t_shutdown_plug_rem, 255);
+ S(mbhc_nsa, 4);
+ S(mbhc_navg, 4);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_DET_PTR(tabla_cal)->X) = (Y))
+ S(mic_current, TABLA_PID_MIC_5_UA);
+ S(hph_current, TABLA_PID_MIC_5_UA);
+ S(t_mic_pid, 100);
+ S(t_ins_complete, 250);
+ S(t_ins_retry, 200);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla_cal)->X) = (Y))
+ S(v_no_mic, 30);
+ S(v_hs_max, 1450);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal)->X) = (Y))
+ S(c[0], 6);
+ S(c[1], 10);
+ S(c[2], 10);
+ S(c[3], 14);
+ S(c[4], 14);
+ S(c[5], 16);
+ S(c[6], 0);
+ S(c[7], 0);
+ S(nc, 5);
+ S(n_meas, 11);
+ S(mbhc_nsc, 11);
+ S(num_btn, TABLA_MBHC_DEF_BUTTONS);
+ S(v_btn_press_delta_sta, 100);
+ S(v_btn_press_delta_cic, 50);
+#undef S
+ btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal);
+ btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
+ btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
+ btn_low[0] = 0;
+ btn_high[0] = 40;
+ btn_low[1] = 60;
+ btn_high[1] = 140;
+ btn_low[2] = 160;
+ btn_high[2] = 240;
+ n_cic = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_CIC);
+ n_cic[0] = 120;
+ n_cic[1] = 94;
+ gain = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_GAIN);
+ gain[0] = 11;
+ gain[1] = 9;
+
+ return tabla_cal;
+}
+
static int msm8960_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
int err;
@@ -618,7 +682,9 @@
return err;
}
- tabla_hs_detect(codec, &hs_jack, &button_jack, &tabla_cal);
+ tabla_hs_detect(codec, &hs_jack, &button_jack, tabla_mbhc_cal,
+ TABLA_MICBIAS2, msm8960_enable_codec_ext_clk, 0,
+ TABLA_EXT_CLK_RATE);
return 0;
}
@@ -1169,9 +1235,17 @@
pr_err("%s: Not the right machine type\n", __func__);
return -ENODEV ;
}
+
+ tabla_mbhc_cal = def_tabla_mbhc_cal();
+ if (!tabla_mbhc_cal) {
+ pr_err("Calibration data allocation failed\n");
+ return -ENOMEM;
+ }
+
msm8960_snd_device = platform_device_alloc("soc-audio", 0);
if (!msm8960_snd_device) {
pr_err("Platform device allocation failed\n");
+ kfree(tabla_mbhc_cal);
return -ENOMEM;
}
@@ -1179,6 +1253,7 @@
ret = platform_device_add(msm8960_snd_device);
if (ret) {
platform_device_put(msm8960_snd_device);
+ kfree(tabla_mbhc_cal);
return ret;
}
@@ -1201,6 +1276,7 @@
}
msm8960_free_headset_mic_gpios();
platform_device_unregister(msm8960_snd_device);
+ kfree(tabla_mbhc_cal);
}
module_exit(msm8960_audio_exit);
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index de63fa0..2acf59e 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.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
@@ -52,8 +52,8 @@
static int voice_send_cvp_register_vol_cal_table_cmd(struct voice_data *v);
static int voice_send_cvp_deregister_vol_cal_table_cmd(struct voice_data *v);
static int voice_send_set_widevoice_enable_cmd(struct voice_data *v);
-static int voice_send_set_slowtalk_enable_cmd(struct voice_data *v);
-
+static int voice_send_set_pp_enable_cmd(struct voice_data *v,
+ uint32_t module_id, int enable);
static int voice_cvs_stop_playback(struct voice_data *v);
static int voice_cvs_start_playback(struct voice_data *v);
static int voice_cvs_start_record(struct voice_data *v, uint32_t rec_mode);
@@ -1764,9 +1764,10 @@
return -EINVAL;
}
-static int voice_send_set_slowtalk_enable_cmd(struct voice_data *v)
+static int voice_send_set_pp_enable_cmd(struct voice_data *v,
+ uint32_t module_id, int enable)
{
- struct cvs_set_slowtalk_enable_cmd cvs_set_st_cmd;
+ struct cvs_set_pp_enable_cmd cvs_set_pp_cmd;
int ret = 0;
void *apr_cvs;
u16 cvs_handle;
@@ -1784,24 +1785,26 @@
cvs_handle = voice_get_cvs_handle(v);
/* fill in the header */
- cvs_set_st_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ cvs_set_pp_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
- cvs_set_st_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(cvs_set_st_cmd) - APR_HDR_SIZE);
- cvs_set_st_cmd.hdr.src_port = v->session_id;
- cvs_set_st_cmd.hdr.dest_port = cvs_handle;
- cvs_set_st_cmd.hdr.token = 0;
- cvs_set_st_cmd.hdr.opcode = VSS_ICOMMON_CMD_SET_UI_PROPERTY;
+ cvs_set_pp_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_set_pp_cmd) - APR_HDR_SIZE);
+ cvs_set_pp_cmd.hdr.src_port = v->session_id;
+ cvs_set_pp_cmd.hdr.dest_port = cvs_handle;
+ cvs_set_pp_cmd.hdr.token = 0;
+ cvs_set_pp_cmd.hdr.opcode = VSS_ICOMMON_CMD_SET_UI_PROPERTY;
- cvs_set_st_cmd.vss_set_st.module_id = MODULE_ID_VOICE_MODULE_ST;
- cvs_set_st_cmd.vss_set_st.param_id = VOICE_PARAM_MOD_ENABLE;
- cvs_set_st_cmd.vss_set_st.param_size = MOD_ENABLE_PARAM_LEN;
- cvs_set_st_cmd.vss_set_st.reserved = 0;
- cvs_set_st_cmd.vss_set_st.enable = v->st_enable;
- cvs_set_st_cmd.vss_set_st.reserved_field = 0;
+ cvs_set_pp_cmd.vss_set_pp.module_id = module_id;
+ cvs_set_pp_cmd.vss_set_pp.param_id = VOICE_PARAM_MOD_ENABLE;
+ cvs_set_pp_cmd.vss_set_pp.param_size = MOD_ENABLE_PARAM_LEN;
+ cvs_set_pp_cmd.vss_set_pp.reserved = 0;
+ cvs_set_pp_cmd.vss_set_pp.enable = enable;
+ cvs_set_pp_cmd.vss_set_pp.reserved_field = 0;
+ pr_debug("voice_send_set_pp_enable_cmd, module_id=%d, enable=%d\n",
+ module_id, enable);
v->cvs_state = CMD_STATUS_FAIL;
- ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_st_cmd);
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_pp_cmd);
if (ret < 0) {
pr_err("Fail: sending cvs set slowtalk enable,\n");
goto fail;
@@ -1918,7 +1921,11 @@
/* enable slowtalk if st_enable is set */
if (v->st_enable)
- voice_send_set_slowtalk_enable_cmd(v);
+ voice_send_set_pp_enable_cmd(v, MODULE_ID_VOICE_MODULE_ST,
+ v->st_enable);
+ if (v->fens_enable)
+ voice_send_set_pp_enable_cmd(v, MODULE_ID_VOICE_MODULE_FENS,
+ v->fens_enable);
if (is_voip_session(v->session_id))
voice_send_netid_timing_cmd(v);
@@ -2836,7 +2843,14 @@
/* enable slowtalk */
if (v->st_enable)
- voice_send_set_slowtalk_enable_cmd(v);
+ voice_send_set_pp_enable_cmd(v,
+ MODULE_ID_VOICE_MODULE_ST,
+ v->st_enable);
+ /* enable FENS */
+ if (v->fens_enable)
+ voice_send_set_pp_enable_cmd(v,
+ MODULE_ID_VOICE_MODULE_FENS,
+ v->fens_enable);
get_sidetone_cal(&sidetone_cal_data);
if (v->dev_tx.port_id != RT_PROXY_PORT_001_TX &&
@@ -2973,7 +2987,7 @@
return ret;
}
-int voc_set_slowtalk_enable(uint16_t session_id, uint32_t st_enable)
+int voc_set_pp_enable(uint16_t session_id, uint32_t module_id, uint32_t enable)
{
struct voice_data *v = voice_get_session(session_id);
int ret = 0;
@@ -2985,18 +2999,27 @@
}
mutex_lock(&v->lock);
+ if (module_id == MODULE_ID_VOICE_MODULE_ST)
+ v->st_enable = enable;
+ else if (module_id == MODULE_ID_VOICE_MODULE_FENS)
+ v->fens_enable = enable;
- v->st_enable = st_enable;
-
- if (v->voc_state == VOC_RUN)
- ret = voice_send_set_slowtalk_enable_cmd(v);
-
+ if (v->voc_state == VOC_RUN) {
+ if (module_id == MODULE_ID_VOICE_MODULE_ST)
+ ret = voice_send_set_pp_enable_cmd(v,
+ MODULE_ID_VOICE_MODULE_ST,
+ enable);
+ else if (module_id == MODULE_ID_VOICE_MODULE_FENS)
+ ret = voice_send_set_pp_enable_cmd(v,
+ MODULE_ID_VOICE_MODULE_FENS,
+ enable);
+ }
mutex_unlock(&v->lock);
return ret;
}
-uint32_t voc_get_slowtalk_enable(uint16_t session_id)
+int voc_get_pp_enable(uint16_t session_id, uint32_t module_id)
{
struct voice_data *v = voice_get_session(session_id);
int ret = 0;
@@ -3008,8 +3031,10 @@
}
mutex_lock(&v->lock);
-
- ret = v->st_enable;
+ if (module_id == MODULE_ID_VOICE_MODULE_ST)
+ ret = v->st_enable;
+ else if (module_id == MODULE_ID_VOICE_MODULE_FENS)
+ ret = v->fens_enable;
mutex_unlock(&v->lock);
diff --git a/sound/soc/msm/qdsp6/q6voice.h b/sound/soc/msm/qdsp6/q6voice.h
index d330ada..2dc08d6 100644
--- a/sound/soc/msm/qdsp6/q6voice.h
+++ b/sound/soc/msm/qdsp6/q6voice.h
@@ -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
@@ -323,6 +323,7 @@
#define VSS_ISTREAM_CMD_SET_ENC_DTX_MODE 0x0001101D
/* Set encoder DTX mode. */
+#define MODULE_ID_VOICE_MODULE_FENS 0x00010EEB
#define MODULE_ID_VOICE_MODULE_ST 0x00010EE3
#define VOICE_PARAM_MOD_ENABLE 0x00010E00
#define MOD_ENABLE_PARAM_LEN 4
@@ -501,7 +502,7 @@
/* Size of the calibration data in bytes. */
};
-struct vss_icommon_cmd_set_ui_property_st_enable_t {
+struct vss_icommon_cmd_set_ui_property_enable_t {
uint32_t module_id;
/* Unique ID of the module. */
uint32_t param_id;
@@ -573,9 +574,9 @@
struct apr_hdr hdr;
} __packed;
-struct cvs_set_slowtalk_enable_cmd {
+struct cvs_set_pp_enable_cmd {
struct apr_hdr hdr;
- struct vss_icommon_cmd_set_ui_property_st_enable_t vss_set_st;
+ struct vss_icommon_cmd_set_ui_property_enable_t vss_set_pp;
} __packed;
struct cvs_start_record_cmd {
struct apr_hdr hdr;
@@ -832,6 +833,8 @@
uint8_t wv_enable;
/* slowtalk enable value */
uint32_t st_enable;
+ /* FENC enable value */
+ uint32_t fens_enable;
struct voice_dev_route_state voc_route_state;
@@ -886,8 +889,8 @@
};
/* called by alsa driver */
-int voc_set_slowtalk_enable(uint16_t session_id, uint32_t st_enable);
-uint32_t voc_get_slowtalk_enable(uint16_t session_id);
+int voc_set_pp_enable(uint16_t session_id, uint32_t module_id, uint32_t enable);
+int voc_get_pp_enable(uint16_t session_id, uint32_t module_id);
int voc_set_widevoice_enable(uint16_t session_id, uint32_t wv_enable);
uint32_t voc_get_widevoice_enable(uint16_t session_id);
uint8_t voc_get_tty_mode(uint16_t session_id);