Merge "msm: clock-8974: Add edp clocks to the lookup table and update clock rates"
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 3c8cb1b..cb2c1e1 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -135,6 +135,25 @@
- qcom,msm_bus,vectors: Arrays of unsigned integers representing:
master-id, slave-id, arbitrated bandwidth,
instantaneous bandwidth
+* wcd9xxx_intc
+
+Required properties:
+
+ - compatible : "qcom,wcd9xxx-irq"
+
+ - interrupt-controller : Mark this device node as an interrupt
+ controller
+
+ - #interrupt-cells : Should be 1
+
+ - interrupt-parent : Parent interrupt controller
+
+ - interrupts : Interrupt number on the parent
+ interrupt controller
+
+ - interrupt-names : Name of interrupt on the parent
+ interrupt controller
+
Example:
qcom,msm-pcm {
@@ -245,6 +264,15 @@
<11 604 32505856 325058560>;
};
+ wcd9xxx_intc: wcd9xxx-irq {
+ compatible = "qcom,wcd9xxx-irq";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <72 0>;
+ interrupt-names = "cdc-int";
+ };
+
* MSM8974 ASoC Machine driver
Required properties:
diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt
index 08f7312..7dde34f 100644
--- a/Documentation/mmc/mmc-dev-attrs.txt
+++ b/Documentation/mmc/mmc-dev-attrs.txt
@@ -25,6 +25,15 @@
running parallel lmdd write and lmdd read operations and calculating
the max number of packed writes requests.
+ min_sectors_to_check_bkops_status This attribute is used to
+ determine whether the status bit that indicates the need for BKOPS
+ should be checked. The value is stored in this attribute represents
+ the minimum number of sectors that needs to be changed in the device
+ (written or discarded) in order to require the status-bit of BKOPS
+ to be checked. The value can modified via sysfs by writing the
+ required value to:
+ /sys/block/<block_dev_name>/min_sectors_to_check_bkops_status
+
SD and MMC Device Attributes
============================
diff --git a/arch/arm/boot/dts/msm8974-liquid.dts b/arch/arm/boot/dts/msm8974-liquid.dts
index 2abc1d5..bf4adaf 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dts
+++ b/arch/arm/boot/dts/msm8974-liquid.dts
@@ -22,27 +22,59 @@
serial@f991e000 {
status = "ok";
};
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+
+ home {
+ label = "home";
+ gpios = <&pm8941_gpios 1 0x1>;
+ linux,input-type = <1>;
+ linux,code = <102>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_down {
+ label = "volume_down";
+ gpios = <&pm8941_gpios 2 0x1>;
+ linux,input-type = <1>;
+ linux,code = <114>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&pm8941_gpios 5 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
};
&pm8941_gpios {
gpio@c000 { /* GPIO 1 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
};
gpio@c100 { /* GPIO 2 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
};
gpio@c200 { /* GPIO 3 */
- qcom,mode = <0>;
- qcom,pull = <0>;
- qcom,vin-sel = <2>;
- qcom,select = <0>;
};
gpio@c300 { /* GPIO 4 */
- qcom,mode = <0>;
- qcom,pull = <0>;
- qcom,vin-sel = <2>;
- qcom,select = <0>;
};
gpio@c400 { /* GPIO 5 */
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 8e6f1e6..9770ecf 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -42,6 +42,15 @@
reg = <0xfd510000 0x4000>;
};
+ wcd9xxx_intc: wcd9xxx-irq {
+ compatible = "qcom,wcd9xxx-irq";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <72 0>;
+ interrupt-names = "cdc-int";
+ };
+
timer {
compatible = "qcom,msm-qtimer", "arm,armv7-timer";
interrupts = <1 2 0 1 3 0>;
@@ -268,6 +277,9 @@
compatible = "qcom,taiko-slim-pgd";
elemental-addr = [00 01 A0 00 17 02];
+ interrupt-parent = <&wcd9xxx_intc>;
+ interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28>;
+
qcom,cdc-reset-gpio = <&msmgpio 63 0>;
cdc-vdd-buck-supply = <&pm8941_s2>;
@@ -906,9 +918,9 @@
qcom,ipi-ping = <1>;
};
- qcom,tz-log@fe805720 {
+ qcom,tz-log@fc03000 {
compatible = "qcom,tz-log";
- reg = <0xfe805720 0x1000>;
+ reg = <0x0fc03000 0x1000>;
};
qcom,venus@fdce0000 {
diff --git a/arch/arm/boot/dts/msm8974_pm.dtsi b/arch/arm/boot/dts/msm8974_pm.dtsi
index f108d37..b2f3fec 100644
--- a/arch/arm/boot/dts/msm8974_pm.dtsi
+++ b/arch/arm/boot/dts/msm8974_pm.dtsi
@@ -28,6 +28,8 @@
qcom,saw2-spm-dly= <0x20000400>;
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d0 c0 a0 90 03 d0 98 a2 c0
+ 0b 00 42 1b 0f];
qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
10 0b 30 06 26 30 0f];
qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
@@ -49,6 +51,8 @@
qcom,saw2-spm-dly= <0x20000400>;
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d0 c0 a0 90 03 d0 98 a2 c0
+ 0b 00 42 1b 0f];
qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
10 0b 30 06 26 30 0f];
qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
@@ -70,6 +74,8 @@
qcom,saw2-spm-dly= <0x20000400>;
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d0 c0 a0 90 03 d0 98 a2 c0
+ 0b 00 42 1b 0f];
qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
10 0b 30 06 26 30 0f];
qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
@@ -91,6 +97,8 @@
qcom,saw2-spm-dly= <0x20000400>;
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d0 c0 a0 90 03 d0 98 a2 c0
+ 0b 00 42 1b 0f];
qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
10 0b 30 06 26 30 0f];
qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
@@ -183,6 +191,22 @@
qcom,lpm-level@1 {
reg = <0x1>;
+ qcom,mode = <4>; /* MSM_PM_SLEEP_MODE_RETENTION*/
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <3>; /* ACTIVE */
+ qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <5>; /* MAX */
+ qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
+ qcom,latency-us = <1500>;
+ qcom,ss-power = <200>;
+ qcom,energy-overhead = <576000>;
+ qcom,time-overhead = <2000>;
+ };
+
+
+ qcom,lpm-level@2 {
+ reg = <0x2>;
qcom,mode = <2>; /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
qcom,xo = <1>; /* ON */
qcom,l2 = <3>; /* ACTIVE */
@@ -196,8 +220,8 @@
qcom,time-overhead = <2000>;
};
- qcom,lpm-level@2 {
- reg = <0x2>;
+ qcom,lpm-level@3 {
+ reg = <0x3>;
qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <1>; /* ON */
qcom,l2 = <1>; /* GDHS */
@@ -211,8 +235,8 @@
qcom,time-overhead = <8500>;
};
- qcom,lpm-level@3 {
- reg = <0x3>;
+ qcom,lpm-level@4 {
+ reg = <0x4>;
qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <1>; /* ON */
qcom,l2 = <0>; /* OFF */
@@ -226,8 +250,8 @@
qcom,time-overhead = <9000>;
};
- qcom,lpm-level@4 {
- reg = <0x4>;
+ qcom,lpm-level@5 {
+ reg = <0x5>;
qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <1>; /* ON */
qcom,l2 = <0>; /* OFF */
@@ -241,8 +265,8 @@
qcom,time-overhead = <10000>;
};
- qcom,lpm-level@5 {
- reg = <0x5>;
+ qcom,lpm-level@6 {
+ reg = <0x6>;
qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <0>; /* OFF */
qcom,l2 = <1>; /* GDHS */
@@ -256,8 +280,8 @@
qcom,time-overhead = <12000>;
};
- qcom,lpm-level@6 {
- reg = <0x6>;
+ qcom,lpm-level@7 {
+ reg = <0x7>;
qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <0>; /* OFF */
qcom,l2 = <0>; /* OFF */
@@ -271,8 +295,8 @@
qcom,time-overhead = <18000>;
};
- qcom,lpm-level@7 {
- reg = <0x7>;
+ qcom,lpm-level@8 {
+ reg = <0x8>;
qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <0>; /* OFF */
qcom,l2 = <0>; /* OFF */
@@ -286,8 +310,8 @@
qcom,time-overhead = <23500>;
};
- qcom,lpm-level@8 {
- reg = <0x8>;
+ qcom,lpm-level@9 {
+ reg = <0x9>;
qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <0>; /* OFF */
qcom,l2 = <0>; /* OFF */
diff --git a/arch/arm/boot/dts/msm9625-regulator.dtsi b/arch/arm/boot/dts/msm9625-regulator.dtsi
index 9184dfe..1b5b03b 100644
--- a/arch/arm/boot/dts/msm9625-regulator.dtsi
+++ b/arch/arm/boot/dts/msm9625-regulator.dtsi
@@ -184,6 +184,7 @@
regulator-max-microvolt = <7>;
qcom,use-voltage-corner;
status = "okay";
+ qcom,consumer-supplies = "vdd_dig", "";
};
pm8019_l10_corner_ao: regulator-l10-corner-ao {
compatible = "qcom,rpm-regulator-smd";
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index d7cdbc4..b439ec6 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -48,10 +48,11 @@
CONFIG_HIGHMEM=y
CONFIG_VMALLOC_RESERVE=0x19000000
CONFIG_USE_OF=y
+CONFIG_CPU_IDLE=y
CONFIG_VFP=y
CONFIG_NEON=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-# CONFIG_SUSPEND is not set
+CONFIG_PM_RUNTIME=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 9f0c30b..593b41e 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -358,6 +358,9 @@
select MSM_RPM_SMD
select MSM_NATIVE_RESTART
select MSM_RESTART_V2
+ select MSM_SPM_V2
+ select MSM_PM8X60 if PM
+ select MSM_SCM if SMP
select MULTI_IRQ_HANDLER
select GPIO_MSM_V3
select MAY_HAVE_SPARSE_IRQ
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 2424b53..e6c6ca6 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -209,6 +209,7 @@
obj-$(CONFIG_ARCH_MSM8960) += cpuidle.o
obj-$(CONFIG_ARCH_MSM8X60) += cpuidle.o
obj-$(CONFIG_ARCH_MSM9615) += cpuidle.o
+ obj-$(CONFIG_ARCH_MSM9625) += cpuidle.o
obj-$(CONFIG_ARCH_MSM8974) += cpuidle.o
endif
@@ -318,6 +319,7 @@
endif
ifdef CONFIG_MSM_RPM_SMD
obj-$(CONFIG_ARCH_MSM8974) += lpm_levels.o lpm_resources.o
+ obj-$(CONFIG_ARCH_MSM9625) += lpm_levels.o lpm_resources.o
endif
obj-$(CONFIG_MSM_MPM_OF) += mpm-of.o
obj-$(CONFIG_MSM_MPM) += mpm.o
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8917.c b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
index b7f554c..8898b50 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8917.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
@@ -551,7 +551,7 @@
RPM_SMPS(S8, 1, 1, 1, 2050000, 2050000, NULL, 100000, 1p60, NONE, NONE),
/* ID a_on pd ss min_uV max_uV supply sys_uA init_ip */
- RPM_LDO(L1, 1, 1, 0, 1050000, 1050000, "8917_s4", 0, 10000),
+ RPM_LDO(L1, 0, 1, 0, 1050000, 1050000, "8917_s4", 0, 10000),
RPM_LDO(L2, 0, 1, 0, 1200000, 1200000, "8917_s4", 0, 0),
RPM_LDO(L3, 0, 1, 0, 3075000, 3075000, NULL, 0, 0),
RPM_LDO(L4, 1, 1, 0, 1800000, 1800000, NULL, 10000, 10000),
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 8568340..50b59e1 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -128,6 +128,12 @@
.dir = GPIOMUX_OUT_LOW,
};
+static struct gpiomux_setting taiko_int = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
static struct msm_gpiomux_config msm_touch_configs[] __initdata = {
{
.gpio = 60, /* TOUCH RESET */
@@ -344,6 +350,21 @@
},
};
+static struct gpiomux_setting sd_card_det_config = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ .dir = GPIOMUX_IN,
+};
+
+static struct msm_gpiomux_config sd_card_det __initdata = {
+ .gpio = 62,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sd_card_det_config,
+ [GPIOMUX_SUSPENDED] = &sd_card_det_config,
+ },
+};
+
static struct msm_gpiomux_config msm_sensor_configs[] __initdata = {
{
.gpio = 15, /* CAM_MCLK0 */
@@ -516,7 +537,13 @@
.settings = {
[GPIOMUX_SUSPENDED] = &taiko_reset,
},
- }
+ },
+ {
+ .gpio = 72, /* CDC_INT */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &taiko_int,
+ },
+ },
};
void __init msm_8974_init_gpiomux(void)
@@ -543,6 +570,8 @@
msm_gpiomux_install(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs));
+ msm_gpiomux_install(&sd_card_det, 1);
+
msm_gpiomux_install(msm_taiko_config, ARRAY_SIZE(msm_taiko_config));
msm_gpiomux_install(msm_hdmi_configs, ARRAY_SIZE(msm_hdmi_configs));
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index dcc0d01..7fe45b8 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -27,6 +27,7 @@
#include <linux/regulator/machine.h>
#include <linux/regulator/krait-regulator.h>
#include <linux/msm_thermal.h>
+#include <linux/mfd/wcd9xxx/core.h>
#include <asm/mach/map.h>
#include <asm/hardware/gic.h>
#include <mach/board.h>
@@ -488,6 +489,7 @@
{ .compatible = "qcom,msm-qgic2", .data = gic_of_init, },
{ .compatible = "qcom,msm-gpio", .data = msm_gpio_of_init, },
{ .compatible = "qcom,spmi-pmic-arb", .data = qpnpint_of_init, },
+ { .compatible = "qcom,wcd9xxx-irq", .data = wcd9xxx_irq_of_init, },
{}
};
static struct of_device_id mpm_match[] __initdata = {
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 2c641ed..90428ce 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -39,6 +39,8 @@
#include <mach/rpm-regulator-smd.h>
#include "clock.h"
#include "modem_notifier.h"
+#include "lpm_resources.h"
+#include "spm.h"
#define MSM_KERNEL_EBI_SIZE 0x51000
@@ -69,7 +71,6 @@
.paddr_to_memtype = msm9625_paddr_to_memtype,
};
-
#define L2CC_AUX_CTRL ((0x1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) | \
(0x2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | \
(0x1 << L2X0_AUX_CTRL_EVNT_MON_BUS_EN_SHIFT))
@@ -285,7 +286,9 @@
msm_init_modem_notifier_list();
msm_smd_init();
msm_rpm_driver_init();
+ msm_lpmrs_module_init();
rpm_regulator_smd_driver_init();
+ msm_spm_device_init();
}
void __init msm9625_init(void)
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 93e801b..b21e60e 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -632,7 +632,6 @@
#define CXO_ID 0x0
#define QDSS_ID 0x1
-#define RPM_SCALING_ENABLE_ID 0x2
#define PNOC_ID 0x0
#define SNOC_ID 0x1
@@ -5751,24 +5750,6 @@
#define APCS_GCC_CC_PHYS 0xF9011000
#define APCS_GCC_CC_SIZE SZ_4K
-static void __init enable_rpm_scaling(void)
-{
- int rc, value = 0x1;
- struct msm_rpm_kvp kvp = {
- .key = RPM_SMD_KEY_ENABLE,
- .data = (void *)&value,
- .length = sizeof(value),
- };
-
- rc = msm_rpm_send_message_noirq(MSM_RPM_CTX_SLEEP_SET,
- RPM_MISC_CLK_TYPE, RPM_SCALING_ENABLE_ID, &kvp, 1);
- WARN(rc < 0, "RPM clock scaling (sleep set) did not enable!\n");
-
- rc = msm_rpm_send_message_noirq(MSM_RPM_CTX_ACTIVE_SET,
- RPM_MISC_CLK_TYPE, RPM_SCALING_ENABLE_ID, &kvp, 1);
- WARN(rc < 0, "RPM clock scaling (active set) did not enable!\n");
-}
-
static void __init msm8974_clock_pre_init(void)
{
virt_bases[GCC_BASE] = ioremap(GCC_CC_PHYS, GCC_CC_SIZE);
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index e06eb4b..daf83e2 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -297,6 +297,27 @@
return HANDOFF_ENABLED_CLK;
}
+#define RPM_MISC_CLK_TYPE 0x306b6c63
+#define RPM_SCALING_ENABLE_ID 0x2
+
+void enable_rpm_scaling(void)
+{
+ int rc, value = 0x1;
+ struct msm_rpm_kvp kvp = {
+ .key = RPM_SMD_KEY_ENABLE,
+ .data = (void *)&value,
+ .length = sizeof(value),
+ };
+
+ rc = msm_rpm_send_message_noirq(MSM_RPM_CTX_SLEEP_SET,
+ RPM_MISC_CLK_TYPE, RPM_SCALING_ENABLE_ID, &kvp, 1);
+ WARN(rc < 0, "RPM clock scaling (sleep set) did not enable!\n");
+
+ rc = msm_rpm_send_message_noirq(MSM_RPM_CTX_ACTIVE_SET,
+ RPM_MISC_CLK_TYPE, RPM_SCALING_ENABLE_ID, &kvp, 1);
+ WARN(rc < 0, "RPM clock scaling (active set) did not enable!\n");
+}
+
struct clk_ops clk_ops_rpm = {
.enable = rpm_clk_enable,
.disable = rpm_clk_disable,
diff --git a/arch/arm/mach-msm/clock-rpm.h b/arch/arm/mach-msm/clock-rpm.h
index 2f0b729..252e8cb 100644
--- a/arch/arm/mach-msm/clock-rpm.h
+++ b/arch/arm/mach-msm/clock-rpm.h
@@ -54,6 +54,12 @@
return container_of(clk, struct rpm_clk, c);
}
+/*
+ * RPM scaling enable function used for target that has an RPM resource for
+ * rpm clock scaling enable.
+ */
+void enable_rpm_scaling(void);
+
extern struct clk_rpmrs_data clk_rpmrs_data;
extern struct clk_rpmrs_data clk_rpmrs_data_smd;
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index 8218a42..4854fc48 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -22,6 +22,18 @@
#include "pm.h"
#include "rpm-notifier.h"
+
+enum {
+ MSM_LPM_LVL_DBG_SUSPEND_LIMITS = BIT(0),
+ MSM_LPM_LVL_DBG_IDLE_LIMITS = BIT(1),
+};
+
+static int msm_lpm_lvl_dbg_msk;
+
+module_param_named(
+ debug_mask, msm_lpm_lvl_dbg_msk, int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
static struct msm_rpmrs_level *msm_lpm_levels;
static int msm_lpm_level_count;
@@ -41,6 +53,7 @@
bool from_idle, bool notify_rpm)
{
int ret = 0;
+ int debug_mask;
struct msm_rpmrs_limits *l = (struct msm_rpmrs_limits *)limits;
ret = msm_rpm_enter_sleep();
@@ -49,6 +62,21 @@
__func__, ret);
goto bail;
}
+ if (from_idle)
+ debug_mask = msm_lpm_lvl_dbg_msk &
+ MSM_LPM_LVL_DBG_IDLE_LIMITS;
+ else
+ debug_mask = msm_lpm_lvl_dbg_msk &
+ MSM_LPM_LVL_DBG_SUSPEND_LIMITS;
+
+ if (debug_mask)
+ pr_info("%s(): pxo:%d l2:%d mem:0x%x(0x%x) dig:0x%x(0x%x)\n",
+ __func__, l->pxo, l->l2_cache,
+ l->vdd_mem_lower_bound,
+ l->vdd_mem_upper_bound,
+ l->vdd_dig_lower_bound,
+ l->vdd_dig_upper_bound);
+
ret = msm_lpmrs_enter_sleep(sclk_count, l, from_idle, notify_rpm);
bail:
return ret;
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 0339c21..5c40750 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -781,11 +781,17 @@
switch (mode) {
case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
+ if (num_online_cpus() > 1) {
+ allow = false;
+ break;
+ }
+ /* fall through */
case MSM_PM_SLEEP_MODE_RETENTION:
if (!allow)
break;
- if (num_online_cpus() > 1) {
+ if (msm_pm_retention_tz_call &&
+ num_online_cpus() > 1) {
allow = false;
break;
}
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 969af98..0beb952 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -35,6 +35,8 @@
HW_PLATFORM_LIQUID = 9,
/* Dragonboard platform id is assigned as 10 in CDT */
HW_PLATFORM_DRAGON = 10,
+ HW_PLATFORM_HRD = 13,
+ HW_PLATFORM_DTV = 14,
HW_PLATFORM_INVALID
};
@@ -47,7 +49,9 @@
[HW_PLATFORM_SVLTE_SURF] = "SLVTE_SURF",
[HW_PLATFORM_MTP] = "MTP",
[HW_PLATFORM_LIQUID] = "Liquid",
- [HW_PLATFORM_DRAGON] = "Dragon"
+ [HW_PLATFORM_DRAGON] = "Dragon",
+ [HW_PLATFORM_HRD] = "HRD",
+ [HW_PLATFORM_DTV] = "DTV",
};
enum {
diff --git a/arch/arm/mach-msm/tz_log.c b/arch/arm/mach-msm/tz_log.c
index db797cd..5a7ec69 100644
--- a/arch/arm/mach-msm/tz_log.c
+++ b/arch/arm/mach-msm/tz_log.c
@@ -496,17 +496,23 @@
*/
tzdiag_phy_iobase = readl_relaxed(virt_iobase);
- /*
- * Map the 4KB diagnostic information area
- */
- tzdbg.virt_iobase = devm_ioremap_nocache(&pdev->dev,
- tzdiag_phy_iobase, DEBUG_MAX_RW_BUF);
+ if (!pdev->dev.of_node) {
- if (!tzdbg.virt_iobase) {
- dev_err(&pdev->dev,
- "%s: ERROR could not ioremap: start=%p, len=%u\n",
- __func__, (void *) tzdiag_phy_iobase, DEBUG_MAX_RW_BUF);
- return -ENXIO;
+ /*
+ * Map the 4KB diagnostic information area
+ */
+ tzdbg.virt_iobase = devm_ioremap_nocache(&pdev->dev,
+ tzdiag_phy_iobase, DEBUG_MAX_RW_BUF);
+
+ if (!tzdbg.virt_iobase) {
+ dev_err(&pdev->dev,
+ "%s: ERROR could not ioremap: start=%p, len=%u\n",
+ __func__, (void *) tzdiag_phy_iobase,
+ DEBUG_MAX_RW_BUF);
+ return -ENXIO;
+ }
+ } else {
+ tzdbg.virt_iobase = virt_iobase;
}
ptr = kzalloc(DEBUG_MAX_RW_BUF, GFP_KERNEL);
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.c b/drivers/media/video/msm/vfe/msm_vfe40.c
index e958241..9ffa874 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.c
+++ b/drivers/media/video/msm/vfe/msm_vfe40.c
@@ -4615,19 +4615,19 @@
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_STATS_CS);
- if (qcmd->vfeInterruptStatus0 &
+ if (qcmd->vfeInterruptStatus1 &
VFE_IRQ_STATUS1_SYNC_TIMER0)
v4l2_subdev_notify(&vfe40_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS1_SYNC_TIMER0);
- if (qcmd->vfeInterruptStatus0 &
+ if (qcmd->vfeInterruptStatus1 &
VFE_IRQ_STATUS1_SYNC_TIMER1)
v4l2_subdev_notify(&vfe40_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS1_SYNC_TIMER1);
- if (qcmd->vfeInterruptStatus0 &
+ if (qcmd->vfeInterruptStatus1 &
VFE_IRQ_STATUS1_SYNC_TIMER2)
v4l2_subdev_notify(&vfe40_ctrl->subdev,
NOTIFY_VFE_IRQ,
diff --git a/drivers/media/video/msm_wfd/wfd-ioctl.c b/drivers/media/video/msm_wfd/wfd-ioctl.c
index 04b787a..d8080dd 100644
--- a/drivers/media/video/msm_wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm_wfd/wfd-ioctl.c
@@ -91,6 +91,7 @@
u32 out_buf_size;
struct list_head input_mem_list;
struct wfd_stats stats;
+ struct completion stop_mdp_thread;
};
struct wfd_vid_buffer {
@@ -522,7 +523,7 @@
static int mdp_output_thread(void *data)
{
- int rc = 0;
+ int rc = 0, no_sig_wait = 0;
struct file *filp = (struct file *)data;
struct wfd_inst *inst = filp->private_data;
struct wfd_device *wfd_dev =
@@ -531,6 +532,14 @@
struct mem_region *mregion;
struct vsg_buf_info ibuf_vsg;
while (!kthread_should_stop()) {
+ if (rc) {
+ WFD_MSG_DBG("%s() error in output thread\n", __func__);
+ if (!no_sig_wait) {
+ wait_for_completion(&inst->stop_mdp_thread);
+ no_sig_wait = 1;
+ }
+ continue;
+ }
WFD_MSG_DBG("waiting for mdp output\n");
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev,
core, ioctl, MDP_DQ_BUFFER, (void *)&obuf_mdp);
@@ -540,7 +549,7 @@
WFD_MSG_ERR("MDP reported err %d\n", rc);
WFD_MSG_ERR("Streamoff called\n");
- break;
+ continue;
} else {
wfd_stats_update(&inst->stats,
WFD_STAT_EVENT_MDP_DEQUEUE);
@@ -550,7 +559,7 @@
if (!mregion) {
WFD_MSG_ERR("mdp cookie is null\n");
rc = -EINVAL;
- break;
+ continue;
}
ibuf_vsg.mdp_buf_info = obuf_mdp;
@@ -565,7 +574,7 @@
if (rc) {
WFD_MSG_ERR("Failed to queue frame to vsg\n");
- break;
+ continue;
} else {
wfd_stats_update(&inst->stats,
WFD_STAT_EVENT_VSG_QUEUE);
@@ -599,7 +608,7 @@
WFD_MSG_ERR("Failed to start vsg\n");
goto subdev_start_fail;
}
-
+ init_completion(&inst->stop_mdp_thread);
inst->mdp_task = kthread_run(mdp_output_thread, priv_data,
"mdp_output_thread");
if (IS_ERR(inst->mdp_task)) {
@@ -634,6 +643,7 @@
if (rc)
WFD_MSG_ERR("Failed to stop VSG\n");
+ complete(&inst->stop_mdp_thread);
kthread_stop(inst->mdp_task);
rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
ENCODE_FLUSH, (void *)inst->venc_inst);
diff --git a/drivers/mfd/pm8038-core.c b/drivers/mfd/pm8038-core.c
index 9815f6e..48bc92d 100644
--- a/drivers/mfd/pm8038-core.c
+++ b/drivers/mfd/pm8038-core.c
@@ -33,6 +33,11 @@
#define REG_RTC_BASE 0x11D
#define REG_IRQ_BASE 0x1BB
+#define REG_BATT_ALARM_THRESH 0x023
+#define REG_BATT_ALARM_CTRL1 0x024
+#define REG_BATT_ALARM_CTRL2 0x021
+#define REG_BATT_ALARM_PWM_CTRL 0x020
+
#define REG_SPK_BASE 0x253
#define REG_SPK_REGISTERS 6
@@ -336,6 +341,27 @@
.pdata_size = sizeof(struct pm8xxx_tm_core_data),
};
+static const struct resource batt_alarm_cell_resources[] __devinitconst = {
+ SINGLE_IRQ_RESOURCE("pm8921_batt_alarm_irq", PM8038_BATT_ALARM_IRQ),
+};
+
+static struct pm8xxx_batt_alarm_core_data batt_alarm_cdata = {
+ .irq_name = "pm8921_batt_alarm_irq",
+ .reg_addr_threshold = REG_BATT_ALARM_THRESH,
+ .reg_addr_ctrl1 = REG_BATT_ALARM_CTRL1,
+ .reg_addr_ctrl2 = REG_BATT_ALARM_CTRL2,
+ .reg_addr_pwm_ctrl = REG_BATT_ALARM_PWM_CTRL,
+};
+
+static struct mfd_cell batt_alarm_cell __devinitdata = {
+ .name = PM8XXX_BATT_ALARM_DEV_NAME,
+ .id = -1,
+ .resources = batt_alarm_cell_resources,
+ .num_resources = ARRAY_SIZE(batt_alarm_cell_resources),
+ .platform_data = &batt_alarm_cdata,
+ .pdata_size = sizeof(struct pm8xxx_batt_alarm_core_data),
+};
+
static const struct resource ccadc_cell_resources[] __devinitconst = {
SINGLE_IRQ_RESOURCE("PM8921_BMS_CCADC_EOC", PM8921_BMS_CCADC_EOC),
};
@@ -661,6 +687,13 @@
goto bail;
}
+ ret = mfd_add_devices(pmic->dev, 0, &batt_alarm_cell, 1, NULL,
+ irq_base);
+ if (ret) {
+ pr_err("Failed to add battery alarm subdevice ret=%d\n", ret);
+ goto bail;
+ }
+
if (pdata->ccadc_pdata) {
ccadc_cell.platform_data = pdata->ccadc_pdata;
ccadc_cell.pdata_size =
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index e7e11d0..65537e4 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/mfd/core.h>
#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
@@ -257,13 +258,20 @@
u8 byte[4];
struct mfd_cell *dev;
int size;
+ int num_irqs;
} wcd9xxx_codecs[] = {
- {{0x2, 0x0, 0x0, 0x1}, tabla_devs, ARRAY_SIZE(tabla_devs)},
- {{0x1, 0x0, 0x0, 0x1}, tabla1x_devs, ARRAY_SIZE(tabla1x_devs)},
- {{0x0, 0x0, 0x2, 0x1}, taiko_devs, ARRAY_SIZE(taiko_devs)},
- {{0x0, 0x0, 0x0, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs)},
- {{0x1, 0x0, 0x1, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs)},
- {{0x2, 0x0, 0x1, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs)},
+ {{0x2, 0x0, 0x0, 0x1}, tabla_devs, ARRAY_SIZE(tabla_devs),
+ TABLA_NUM_IRQS},
+ {{0x1, 0x0, 0x0, 0x1}, tabla1x_devs, ARRAY_SIZE(tabla1x_devs),
+ TABLA_NUM_IRQS},
+ {{0x0, 0x0, 0x2, 0x1}, taiko_devs, ARRAY_SIZE(taiko_devs),
+ TAIKO_NUM_IRQS},
+ {{0x0, 0x0, 0x0, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs),
+ SITAR_NUM_IRQS},
+ {{0x1, 0x0, 0x1, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs),
+ SITAR_NUM_IRQS},
+ {{0x2, 0x0, 0x1, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs),
+ SITAR_NUM_IRQS},
};
static void wcd9xxx_bring_up(struct wcd9xxx *wcd9xxx)
@@ -312,8 +320,9 @@
}
}
static int wcd9xxx_check_codec_type(struct wcd9xxx *wcd9xxx,
- struct mfd_cell **wcd9xxx_dev,
- int *wcd9xxx_dev_size)
+ struct mfd_cell **wcd9xxx_dev,
+ int *wcd9xxx_dev_size,
+ int *wcd9xxx_dev_num_irqs)
{
int i;
int ret;
@@ -343,6 +352,7 @@
wcd9xxx_codecs[i].dev->name);
*wcd9xxx_dev = wcd9xxx_codecs[i].dev;
*wcd9xxx_dev_size = wcd9xxx_codecs[i].size;
+ *wcd9xxx_dev_num_irqs = wcd9xxx_codecs[i].num_irqs;
break;
}
i++;
@@ -359,7 +369,7 @@
return ret;
}
-static int wcd9xxx_device_init(struct wcd9xxx *wcd9xxx, int irq)
+static int wcd9xxx_device_init(struct wcd9xxx *wcd9xxx)
{
int ret;
struct mfd_cell *wcd9xxx_dev = NULL;
@@ -379,6 +389,11 @@
wcd9xxx_bring_up(wcd9xxx);
+ ret = wcd9xxx_check_codec_type(wcd9xxx, &wcd9xxx_dev, &wcd9xxx_dev_size,
+ &wcd9xxx->num_irqs);
+ if (ret < 0)
+ goto err_irq;
+
if (wcd9xxx->irq != -1) {
ret = wcd9xxx_irq_init(wcd9xxx);
if (ret) {
@@ -386,11 +401,7 @@
goto err;
}
}
- ret = wcd9xxx_check_codec_type(wcd9xxx, &wcd9xxx_dev,
- &wcd9xxx_dev_size);
- if (ret < 0)
- goto err_irq;
ret = mfd_add_devices(wcd9xxx->dev, -1, wcd9xxx_dev, wcd9xxx_dev_size,
NULL, 0);
if (ret != 0) {
@@ -795,10 +806,12 @@
wcd9xxx->read_dev = wcd9xxx_i2c_read;
wcd9xxx->write_dev = wcd9xxx_i2c_write;
- wcd9xxx->irq = pdata->irq;
- wcd9xxx->irq_base = pdata->irq_base;
+ if (!wcd9xxx->dev->of_node) {
+ wcd9xxx->irq = pdata->irq;
+ wcd9xxx->irq_base = pdata->irq_base;
+ }
- ret = wcd9xxx_device_init(wcd9xxx, wcd9xxx->irq);
+ ret = wcd9xxx_device_init(wcd9xxx);
if (ret) {
pr_err("%s: error, initializing device failed\n", __func__);
goto err_device_init;
@@ -1072,7 +1085,6 @@
pdata->reset_gpio);
goto err;
}
- pdata->irq = -1;
ret = wcd9xxx_dt_parse_slim_interface_dev_info(dev,
&pdata->slimbus_slave_device);
@@ -1163,14 +1175,12 @@
}
wcd9xxx->read_dev = wcd9xxx_slim_read_device;
wcd9xxx->write_dev = wcd9xxx_slim_write_device;
- wcd9xxx->irq = pdata->irq;
- wcd9xxx->irq_base = pdata->irq_base;
wcd9xxx_pgd_la = wcd9xxx->slim->laddr;
-
- if (pdata->num_irqs < TABLA_NUM_IRQS)
- pr_warn("%s: Not enough interrupt lines allocated\n", __func__);
-
wcd9xxx->slim_slave = &pdata->slimbus_slave_device;
+ if (!wcd9xxx->dev->of_node) {
+ wcd9xxx->irq = pdata->irq;
+ wcd9xxx->irq_base = pdata->irq_base;
+ }
ret = slim_add_device(slim->ctrl, wcd9xxx->slim_slave);
if (ret) {
@@ -1190,7 +1200,7 @@
wcd9xxx_inf_la = wcd9xxx->slim_slave->laddr;
wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_SLIMBUS;
- ret = wcd9xxx_device_init(wcd9xxx, wcd9xxx->irq);
+ ret = wcd9xxx_device_init(wcd9xxx);
if (ret) {
pr_err("%s: error, initializing device failed\n", __func__);
goto err_slim_add;
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index e9b2ef3..103c1a3 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -18,8 +18,13 @@
#include <linux/mfd/wcd9xxx/core.h>
#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
#include <linux/mfd/wcd9xxx/wcd9310_registers.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
+#include <linux/delay.h>
+#include <linux/irqdomain.h>
#include <linux/interrupt.h>
-
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
#include <mach/cpuidle.h>
#define BYTE_BIT_MASK(nr) (1UL << ((nr) % BITS_PER_BYTE))
@@ -27,19 +32,18 @@
#define WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS 100
-struct wcd9xxx_irq {
- bool level;
+#ifdef CONFIG_OF
+struct wcd9xxx_irq_drv_data {
+ struct irq_domain *domain;
+ int irq;
};
+#endif
-static struct wcd9xxx_irq wcd9xxx_irqs[TABLA_NUM_IRQS] = {
- [0] = { .level = 1},
-/* All other wcd9xxx interrupts are edge triggered */
-};
-
-static inline int irq_to_wcd9xxx_irq(struct wcd9xxx *wcd9xxx, int irq)
-{
- return irq - wcd9xxx->irq_base;
-}
+static int virq_to_phyirq(struct wcd9xxx *wcd9xxx, int virq);
+static int phyirq_to_virq(struct wcd9xxx *wcd9xxx, int irq);
+static unsigned int wcd9xxx_irq_get_upstream_irq(struct wcd9xxx *wcd9xxx);
+static void wcd9xxx_irq_put_upstream_irq(struct wcd9xxx *wcd9xxx);
+static int wcd9xxx_map_irq(struct wcd9xxx *wcd9xxx, int irq);
static void wcd9xxx_irq_lock(struct irq_data *data)
{
@@ -58,8 +62,9 @@
*/
if (wcd9xxx->irq_masks_cur[i] != wcd9xxx->irq_masks_cache[i]) {
wcd9xxx->irq_masks_cache[i] = wcd9xxx->irq_masks_cur[i];
- wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_MASK0+i,
- wcd9xxx->irq_masks_cur[i]);
+ wcd9xxx_reg_write(wcd9xxx,
+ WCD9XXX_A_INTR_MASK0 + i,
+ wcd9xxx->irq_masks_cur[i]);
}
}
@@ -69,7 +74,7 @@
static void wcd9xxx_irq_enable(struct irq_data *data)
{
struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
- int wcd9xxx_irq = irq_to_wcd9xxx_irq(wcd9xxx, data->irq);
+ int wcd9xxx_irq = virq_to_phyirq(wcd9xxx, data->irq);
wcd9xxx->irq_masks_cur[BIT_BYTE(wcd9xxx_irq)] &=
~(BYTE_BIT_MASK(wcd9xxx_irq));
}
@@ -77,9 +82,14 @@
static void wcd9xxx_irq_disable(struct irq_data *data)
{
struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
- int wcd9xxx_irq = irq_to_wcd9xxx_irq(wcd9xxx, data->irq);
+ int wcd9xxx_irq = virq_to_phyirq(wcd9xxx, data->irq);
wcd9xxx->irq_masks_cur[BIT_BYTE(wcd9xxx_irq)]
- |= BYTE_BIT_MASK(wcd9xxx_irq);
+ |= BYTE_BIT_MASK(wcd9xxx_irq);
+}
+
+static void wcd9xxx_irq_mask(struct irq_data *d)
+{
+ /* do nothing but required as linux calls irq_mask without NULL check */
}
static struct irq_chip wcd9xxx_irq_chip = {
@@ -88,6 +98,7 @@
.irq_bus_sync_unlock = wcd9xxx_irq_sync_unlock,
.irq_disable = wcd9xxx_irq_disable,
.irq_enable = wcd9xxx_irq_enable,
+ .irq_mask = wcd9xxx_irq_mask,
};
enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(struct wcd9xxx *wcd9xxx,
@@ -167,62 +178,72 @@
static void wcd9xxx_irq_dispatch(struct wcd9xxx *wcd9xxx, int irqbit)
{
- if ((irqbit <= TABLA_IRQ_MBHC_INSERTION) &&
- (irqbit >= TABLA_IRQ_MBHC_REMOVAL)) {
- wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_CLEAR0 +
- BIT_BYTE(irqbit), BYTE_BIT_MASK(irqbit));
+ if ((irqbit <= WCD9XXX_IRQ_MBHC_INSERTION) &&
+ (irqbit >= WCD9XXX_IRQ_MBHC_REMOVAL)) {
+ wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_CLEAR0 +
+ BIT_BYTE(irqbit),
+ BYTE_BIT_MASK(irqbit));
if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
- wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_MODE, 0x02);
- handle_nested_irq(wcd9xxx->irq_base + irqbit);
+ wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_MODE, 0x02);
+ handle_nested_irq(phyirq_to_virq(wcd9xxx, irqbit));
} else {
- handle_nested_irq(wcd9xxx->irq_base + irqbit);
- wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_CLEAR0 +
- BIT_BYTE(irqbit), BYTE_BIT_MASK(irqbit));
+ handle_nested_irq(phyirq_to_virq(wcd9xxx, irqbit));
+ wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_CLEAR0 +
+ BIT_BYTE(irqbit),
+ BYTE_BIT_MASK(irqbit));
if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
- wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_MODE, 0x02);
+ wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_MODE, 0x02);
}
}
+static int wcd9xxx_num_irq_regs(const struct wcd9xxx *wcd9xxx)
+{
+ return (wcd9xxx->num_irqs / 8) + ((wcd9xxx->num_irqs % 8) ? 1 : 0);
+}
+
static irqreturn_t wcd9xxx_irq_thread(int irq, void *data)
{
int ret;
- struct wcd9xxx *wcd9xxx = data;
- u8 status[WCD9XXX_NUM_IRQ_REGS];
int i;
+ struct wcd9xxx *wcd9xxx = data;
+ int num_irq_regs = wcd9xxx_num_irq_regs(wcd9xxx);
+ u8 status[num_irq_regs];
if (unlikely(wcd9xxx_lock_sleep(wcd9xxx) == false)) {
dev_err(wcd9xxx->dev, "Failed to hold suspend\n");
return IRQ_NONE;
}
- ret = wcd9xxx_bulk_read(wcd9xxx, TABLA_A_INTR_STATUS0,
- WCD9XXX_NUM_IRQ_REGS, status);
+ ret = wcd9xxx_bulk_read(wcd9xxx, WCD9XXX_A_INTR_STATUS0,
+ num_irq_regs, status);
if (ret < 0) {
dev_err(wcd9xxx->dev, "Failed to read interrupt status: %d\n",
ret);
wcd9xxx_unlock_sleep(wcd9xxx);
return IRQ_NONE;
}
+
/* Apply masking */
- for (i = 0; i < WCD9XXX_NUM_IRQ_REGS; i++)
+ for (i = 0; i < num_irq_regs; i++)
status[i] &= ~wcd9xxx->irq_masks_cur[i];
/* Find out which interrupt was triggered and call that interrupt's
* handler function
*/
- if (status[BIT_BYTE(TABLA_IRQ_SLIMBUS)] &
- BYTE_BIT_MASK(TABLA_IRQ_SLIMBUS))
- wcd9xxx_irq_dispatch(wcd9xxx, TABLA_IRQ_SLIMBUS);
+ if (status[BIT_BYTE(WCD9XXX_IRQ_SLIMBUS)] &
+ BYTE_BIT_MASK(WCD9XXX_IRQ_SLIMBUS))
+ wcd9xxx_irq_dispatch(wcd9xxx, WCD9XXX_IRQ_SLIMBUS);
/* Since codec has only one hardware irq line which is shared by
* codec's different internal interrupts, so it's possible master irq
* handler dispatches multiple nested irq handlers after breaking
* order. Dispatch MBHC interrupts order to follow MBHC state
* machine's order */
- for (i = TABLA_IRQ_MBHC_INSERTION; i >= TABLA_IRQ_MBHC_REMOVAL; i--) {
+ for (i = WCD9XXX_IRQ_MBHC_INSERTION;
+ i >= WCD9XXX_IRQ_MBHC_REMOVAL; i--) {
if (status[BIT_BYTE(i)] & BYTE_BIT_MASK(i))
wcd9xxx_irq_dispatch(wcd9xxx, i);
}
- for (i = TABLA_IRQ_BG_PRECHARGE; i < TABLA_NUM_IRQS; i++) {
+ for (i = WCD9XXX_IRQ_BG_PRECHARGE; i < wcd9xxx->num_irqs; i++) {
if (status[BIT_BYTE(i)] & BYTE_BIT_MASK(i))
wcd9xxx_irq_dispatch(wcd9xxx, i);
}
@@ -231,59 +252,105 @@
return IRQ_HANDLED;
}
+void wcd9xxx_free_irq(struct wcd9xxx *wcd9xxx, int irq, void *data)
+{
+ free_irq(phyirq_to_virq(wcd9xxx, irq), data);
+}
+
+void wcd9xxx_enable_irq(struct wcd9xxx *wcd9xxx, int irq)
+{
+ enable_irq(phyirq_to_virq(wcd9xxx, irq));
+}
+
+void wcd9xxx_disable_irq(struct wcd9xxx *wcd9xxx, int irq)
+{
+ disable_irq_nosync(phyirq_to_virq(wcd9xxx, irq));
+}
+
+void wcd9xxx_disable_irq_sync(struct wcd9xxx *wcd9xxx, int irq)
+{
+ disable_irq(phyirq_to_virq(wcd9xxx, irq));
+}
+
+static int wcd9xxx_irq_setup_downstream_irq(struct wcd9xxx *wcd9xxx)
+{
+ int irq, virq, ret;
+
+ pr_debug("%s: enter\n", __func__);
+
+ for (irq = 0; irq < wcd9xxx->num_irqs; irq++) {
+ /* Map OF irq */
+ virq = wcd9xxx_map_irq(wcd9xxx, irq);
+ pr_debug("%s: irq %d -> %d\n", __func__, irq, virq);
+ if (virq == NO_IRQ) {
+ pr_err("%s, No interrupt specifier for irq %d\n",
+ __func__, irq);
+ return NO_IRQ;
+ }
+
+ ret = irq_set_chip_data(virq, wcd9xxx);
+ if (ret) {
+ pr_err("%s: Failed to configure irq %d (%d)\n",
+ __func__, irq, ret);
+ return ret;
+ }
+
+ if (wcd9xxx->irq_level_high[irq])
+ irq_set_chip_and_handler(virq, &wcd9xxx_irq_chip,
+ handle_level_irq);
+ else
+ irq_set_chip_and_handler(virq, &wcd9xxx_irq_chip,
+ handle_edge_irq);
+
+ irq_set_nested_thread(virq, 1);
+ }
+
+ pr_debug("%s: leave\n", __func__);
+
+ return 0;
+}
+
int wcd9xxx_irq_init(struct wcd9xxx *wcd9xxx)
{
- int ret;
- unsigned int i, cur_irq;
+ int i, ret;
+ u8 irq_level[wcd9xxx_num_irq_regs(wcd9xxx)];
mutex_init(&wcd9xxx->irq_lock);
+ wcd9xxx->irq = wcd9xxx_irq_get_upstream_irq(wcd9xxx);
if (!wcd9xxx->irq) {
- dev_warn(wcd9xxx->dev,
- "No interrupt specified, no interrupts\n");
- wcd9xxx->irq_base = 0;
- return 0;
+ pr_warn("%s: irq driver is not yet initialized\n", __func__);
+ mutex_destroy(&wcd9xxx->irq_lock);
+ return -EPROBE_DEFER;
+ }
+ pr_debug("%s: probed irq %d\n", __func__, wcd9xxx->irq);
+
+ /* Setup downstream IRQs */
+ ret = wcd9xxx_irq_setup_downstream_irq(wcd9xxx);
+ if (ret) {
+ pr_err("%s: Failed to setup downstream IRQ\n", __func__);
+ wcd9xxx_irq_put_upstream_irq(wcd9xxx);
+ return ret;
}
- if (!wcd9xxx->irq_base) {
- dev_err(wcd9xxx->dev,
- "No interrupt base specified, no interrupts\n");
- return 0;
- }
- /* Mask the individual interrupt sources */
- for (i = 0, cur_irq = wcd9xxx->irq_base; i < TABLA_NUM_IRQS; i++,
- cur_irq++) {
+ /* All other wcd9xxx interrupts are edge triggered */
+ wcd9xxx->irq_level_high[0] = true;
- irq_set_chip_data(cur_irq, wcd9xxx);
-
- if (wcd9xxx_irqs[i].level)
- irq_set_chip_and_handler(cur_irq, &wcd9xxx_irq_chip,
- handle_level_irq);
- else
- irq_set_chip_and_handler(cur_irq, &wcd9xxx_irq_chip,
- handle_edge_irq);
-
- irq_set_nested_thread(cur_irq, 1);
-
- /* ARM needs us to explicitly flag the IRQ as valid
- * and will set them noprobe when we do so. */
-#ifdef CONFIG_ARM
- set_irq_flags(cur_irq, IRQF_VALID);
-#else
- set_irq_noprobe(cur_irq);
-#endif
-
+ /* mask all the interrupts */
+ memset(irq_level, 0, wcd9xxx_num_irq_regs(wcd9xxx));
+ for (i = 0; i < wcd9xxx->num_irqs; i++) {
wcd9xxx->irq_masks_cur[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
wcd9xxx->irq_masks_cache[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
- wcd9xxx->irq_level[BIT_BYTE(i)] |= wcd9xxx_irqs[i].level <<
- (i % BITS_PER_BYTE);
+ irq_level[BIT_BYTE(i)] |=
+ wcd9xxx->irq_level_high[i] << (i % BITS_PER_BYTE);
}
- for (i = 0; i < WCD9XXX_NUM_IRQ_REGS; i++) {
+
+ for (i = 0; i < wcd9xxx_num_irq_regs(wcd9xxx); i++) {
/* Initialize interrupt mask and level registers */
- wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_LEVEL0 + i,
- wcd9xxx->irq_level[i]);
- wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_MASK0 + i,
- wcd9xxx->irq_masks_cur[i]);
+ wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_LEVEL0 + i,
+ irq_level[i]);
+ wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_MASK0 + i,
+ wcd9xxx->irq_masks_cur[i]);
}
ret = request_threaded_irq(wcd9xxx->irq, NULL, wcd9xxx_irq_thread,
@@ -308,18 +375,226 @@
free_irq(wcd9xxx->irq, wcd9xxx);
}
- if (ret)
+ if (ret) {
+ pr_err("%s: Failed to init wcd9xxx irq\n", __func__);
+ wcd9xxx_irq_put_upstream_irq(wcd9xxx);
mutex_destroy(&wcd9xxx->irq_lock);
+ }
return ret;
}
+int wcd9xxx_request_irq(struct wcd9xxx *wcd9xxx, int irq, irq_handler_t handler,
+ const char *name, void *data)
+{
+ int virq;
+
+ virq = phyirq_to_virq(wcd9xxx, irq);
+
+ /*
+ * ARM needs us to explicitly flag the IRQ as valid
+ * and will set them noprobe when we do so.
+ */
+#ifdef CONFIG_ARM
+ set_irq_flags(virq, IRQF_VALID);
+#else
+ set_irq_noprobe(virq);
+#endif
+
+ return request_threaded_irq(virq, NULL, handler, IRQF_TRIGGER_RISING,
+ name, data);
+}
+
void wcd9xxx_irq_exit(struct wcd9xxx *wcd9xxx)
{
if (wcd9xxx->irq) {
disable_irq_wake(wcd9xxx->irq);
free_irq(wcd9xxx->irq, wcd9xxx);
+ /* Release parent's of node */
+ wcd9xxx_irq_put_upstream_irq(wcd9xxx);
device_init_wakeup(wcd9xxx->dev, 0);
}
mutex_destroy(&wcd9xxx->irq_lock);
}
+
+#ifndef CONFIG_OF
+static int phyirq_to_virq(struct wcd9xxx *wcd9xxx, int offset)
+{
+ return wcd9xxx->irq_base + offset;
+}
+
+static int virq_to_phyirq(struct wcd9xxx *wcd9xxx, int virq)
+{
+ return virq - wcd9xxx->irq_base;
+}
+
+static unsigned int wcd9xxx_irq_get_upstream_irq(struct wcd9xxx *wcd9xxx)
+{
+ return wcd9xxx->irq;
+}
+
+static void wcd9xxx_irq_put_upstream_irq(struct wcd9xxx *wcd9xxx)
+{
+ /* Do nothing */
+}
+
+static int wcd9xxx_map_irq(struct wcd9xxx *wcd9xxx, int irq)
+{
+ return phyirq_to_virq(wcd9xxx, irq);
+}
+#else
+int __init wcd9xxx_irq_of_init(struct device_node *node,
+ struct device_node *parent)
+{
+ struct wcd9xxx_irq_drv_data *data;
+
+ pr_debug("%s: node %s, node parent %s\n", __func__,
+ node->name, node->parent->name);
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ /*
+ * wcd9xxx_intc interrupt controller supports N to N irq mapping with
+ * single cell binding with irq numbers(offsets) only.
+ * Use irq_domain_simple_ops that has irq_domain_simple_map and
+ * irq_domain_xlate_onetwocell.
+ */
+ data->domain = irq_domain_add_linear(node, WCD9XXX_MAX_NUM_IRQS,
+ &irq_domain_simple_ops, data);
+ if (!data->domain) {
+ kfree(data);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static struct wcd9xxx_irq_drv_data *
+wcd9xxx_get_irq_drv_d(const struct wcd9xxx *wcd9xxx)
+{
+ struct device_node *pnode;
+ struct irq_domain *domain;
+
+ pnode = of_irq_find_parent(wcd9xxx->dev->of_node);
+ /* Shouldn't happen */
+ if (unlikely(!pnode))
+ return NULL;
+
+ domain = irq_find_host(pnode);
+ return (struct wcd9xxx_irq_drv_data *)domain->host_data;
+}
+
+static int phyirq_to_virq(struct wcd9xxx *wcd9xxx, int offset)
+{
+ struct wcd9xxx_irq_drv_data *data;
+
+ data = wcd9xxx_get_irq_drv_d(wcd9xxx);
+ if (!data) {
+ pr_warn("%s: not registered to interrupt controller\n",
+ __func__);
+ return -EINVAL;
+ }
+ return irq_linear_revmap(data->domain, offset);
+}
+
+static int virq_to_phyirq(struct wcd9xxx *wcd9xxx, int virq)
+{
+ struct irq_data *irq_data = irq_get_irq_data(virq);
+ return irq_data->hwirq;
+}
+
+static unsigned int wcd9xxx_irq_get_upstream_irq(struct wcd9xxx *wcd9xxx)
+{
+ struct wcd9xxx_irq_drv_data *data;
+
+ /* Hold parent's of node */
+ if (!of_node_get(of_irq_find_parent(wcd9xxx->dev->of_node)))
+ return -EINVAL;
+
+ data = wcd9xxx_get_irq_drv_d(wcd9xxx);
+ if (!data) {
+ pr_err("%s: interrupt controller is not registerd\n", __func__);
+ return 0;
+ }
+
+ rmb();
+ return data->irq;
+}
+
+static void wcd9xxx_irq_put_upstream_irq(struct wcd9xxx *wcd9xxx)
+{
+ /* Hold parent's of node */
+ of_node_put(of_irq_find_parent(wcd9xxx->dev->of_node));
+}
+
+static int wcd9xxx_map_irq(struct wcd9xxx *wcd9xxx, int irq)
+{
+ return of_irq_to_resource(wcd9xxx->dev->of_node, irq, NULL);
+}
+
+static int __devinit wcd9xxx_irq_probe(struct platform_device *pdev)
+{
+ int irq;
+ struct irq_domain *domain;
+ struct wcd9xxx_irq_drv_data *data;
+ int ret = -EINVAL;
+
+ irq = platform_get_irq_byname(pdev, "cdc-int");
+ if (irq < 0) {
+ dev_err(&pdev->dev, "%s: Couldn't find cdc-int node(%d)\n",
+ __func__, irq);
+ return -EINVAL;
+ } else {
+ dev_dbg(&pdev->dev, "%s: virq = %d\n", __func__, irq);
+ domain = irq_find_host(pdev->dev.of_node);
+ data = (struct wcd9xxx_irq_drv_data *)domain->host_data;
+ data->irq = irq;
+ wmb();
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int wcd9xxx_irq_remove(struct platform_device *pdev)
+{
+ struct irq_domain *domain;
+ struct wcd9xxx_irq_drv_data *data;
+
+ domain = irq_find_host(pdev->dev.of_node);
+ data = (struct wcd9xxx_irq_drv_data *)domain->host_data;
+ data->irq = 0;
+ wmb();
+
+ return 0;
+}
+
+static const struct of_device_id of_match[] = {
+ { .compatible = "qcom,wcd9xxx-irq" },
+ { }
+};
+
+static struct platform_driver wcd9xxx_irq_driver = {
+ .probe = wcd9xxx_irq_probe,
+ .remove = wcd9xxx_irq_remove,
+ .driver = {
+ .name = "wcd9xxx_intc",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(of_match),
+ },
+};
+
+static int wcd9xxx_irq_drv_init(void)
+{
+ return platform_driver_register(&wcd9xxx_irq_driver);
+}
+subsys_initcall(wcd9xxx_irq_drv_init);
+
+static void wcd9xxx_irq_drv_exit(void)
+{
+ platform_driver_unregister(&wcd9xxx_irq_driver);
+}
+module_exit(wcd9xxx_irq_drv_exit);
+#endif /* CONFIG_OF */
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index b9cd8ec..7387d9a 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -121,6 +121,7 @@
struct device_attribute force_ro;
struct device_attribute power_ro_lock;
struct device_attribute num_wr_reqs_to_start_packing;
+ struct device_attribute min_sectors_to_check_bkops_status;
int area_type;
};
@@ -306,6 +307,48 @@
return count;
}
+static ssize_t
+min_sectors_to_check_bkops_status_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+ unsigned int min_sectors_to_check_bkops_status;
+ struct mmc_card *card = md->queue.card;
+ int ret;
+
+ if (!card)
+ return -EINVAL;
+
+ min_sectors_to_check_bkops_status =
+ card->bkops_info.min_sectors_to_queue_delayed_work;
+
+ ret = snprintf(buf, PAGE_SIZE, "%d\n",
+ min_sectors_to_check_bkops_status);
+
+ mmc_blk_put(md);
+ return ret;
+}
+
+static ssize_t
+min_sectors_to_check_bkops_status_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value;
+ struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+ struct mmc_card *card = md->queue.card;
+
+ if (!card)
+ return -EINVAL;
+
+ sscanf(buf, "%d", &value);
+ if (value >= 0)
+ card->bkops_info.min_sectors_to_queue_delayed_work = value;
+
+ mmc_blk_put(md);
+ return count;
+}
+
static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
{
struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
@@ -2316,6 +2359,19 @@
if (ret)
goto power_ro_lock_fail;
+ md->min_sectors_to_check_bkops_status.show =
+ min_sectors_to_check_bkops_status_show;
+ md->min_sectors_to_check_bkops_status.store =
+ min_sectors_to_check_bkops_status_store;
+ sysfs_attr_init(&md->min_sectors_to_check_bkops_status.attr);
+ md->min_sectors_to_check_bkops_status.attr.name =
+ "min_sectors_to_check_bkops_status";
+ md->min_sectors_to_check_bkops_status.attr.mode = S_IRUGO | S_IWUSR;
+ ret = device_create_file(disk_to_dev(md->disk),
+ &md->min_sectors_to_check_bkops_status);
+ if (ret)
+ goto power_ro_lock_fail;
+
return ret;
power_ro_lock_fail:
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 9b9e8cc..7e03e5a 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -291,7 +291,7 @@
return;
if (card->bkops_info.sectors_changed <
- BKOPS_MIN_SECTORS_TO_QUEUE_DELAYED_WORK)
+ card->bkops_info.min_sectors_to_queue_delayed_work)
return;
pr_debug("%s: %s: queueing delayed_bkops_work\n",
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 457db7f..ca8b01c 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1336,6 +1336,8 @@
card->bkops_info.delay_ms,
card->bkops_info.host_suspend_tout_ms/2);
+ card->bkops_info.min_sectors_to_queue_delayed_work =
+ BKOPS_MIN_SECTORS_TO_QUEUE_DELAYED_WORK;
}
}
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 4e92dd7..061418f 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -3,7 +3,8 @@
*
* Copyright (C) 2007 Google Inc,
* Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
- * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ *
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -5450,7 +5451,7 @@
struct mmc_platform_data *pdata;
struct device_node *np = dev->of_node;
u32 bus_width = 0, current_limit = 0;
- u32 *clk_table, *sup_voltages;
+ u32 *clk_table = NULL, *sup_voltages = NULL;
int clk_table_len, sup_volt_len, len;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 817bfbb..0b1a16e 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -52,6 +52,7 @@
#include "f_rmnet_sdio.c"
#include "f_rmnet_smd_sdio.c"
#include "f_rmnet.c"
+#include "f_audio_source.c"
#include "f_mass_storage.c"
#include "u_serial.c"
#include "u_sdio.c"
@@ -1475,6 +1476,68 @@
.ctrlrequest = accessory_function_ctrlrequest,
};
+static int audio_source_function_init(struct android_usb_function *f,
+ struct usb_composite_dev *cdev)
+{
+ struct audio_source_config *config;
+
+ config = kzalloc(sizeof(struct audio_source_config), GFP_KERNEL);
+ if (!config)
+ return -ENOMEM;
+ config->card = -1;
+ config->device = -1;
+ f->config = config;
+ return 0;
+}
+
+static void audio_source_function_cleanup(struct android_usb_function *f)
+{
+ kfree(f->config);
+}
+
+static int audio_source_function_bind_config(struct android_usb_function *f,
+ struct usb_configuration *c)
+{
+ struct audio_source_config *config = f->config;
+
+ return audio_source_bind_config(c, config);
+}
+
+static void audio_source_function_unbind_config(struct android_usb_function *f,
+ struct usb_configuration *c)
+{
+ struct audio_source_config *config = f->config;
+
+ config->card = -1;
+ config->device = -1;
+}
+
+static ssize_t audio_source_pcm_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct android_usb_function *f = dev_get_drvdata(dev);
+ struct audio_source_config *config = f->config;
+
+ /* print PCM card and device numbers */
+ return sprintf(buf, "%d %d\n", config->card, config->device);
+}
+
+static DEVICE_ATTR(pcm, S_IRUGO | S_IWUSR, audio_source_pcm_show, NULL);
+
+static struct device_attribute *audio_source_function_attributes[] = {
+ &dev_attr_pcm,
+ NULL
+};
+
+static struct android_usb_function audio_source_function = {
+ .name = "audio_source",
+ .init = audio_source_function_init,
+ .cleanup = audio_source_function_cleanup,
+ .bind_config = audio_source_function_bind_config,
+ .unbind_config = audio_source_function_unbind_config,
+ .attributes = audio_source_function_attributes,
+};
+
static int android_uasp_connect_cb(bool connect)
{
/*
@@ -1543,6 +1606,7 @@
&rndis_qc_function,
&mass_storage_function,
&accessory_function,
+ &audio_source_function,
&uasp_function,
NULL
};
@@ -2175,6 +2239,11 @@
unsigned long flags;
composite_disconnect(gadget);
+ /* accessory HID support can be active while the
+ accessory function is not actually enabled,
+ so we need to inform it when we are disconnected.
+ */
+ acc_disconnect();
spin_lock_irqsave(&cdev->lock, flags);
dev->connected = 0;
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 0b0ebe7..b3cab7a 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -76,6 +76,8 @@
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
#define ATDTW_SET_DELAY 100 /* 100msec delay */
+#define EP_PRIME_CHECK_DELAY (jiffies + msecs_to_jiffies(1000))
+#define MAX_PRIME_CHECK_RETRY 3 /*Wait for 3sec for EP prime failure */
/* ctrl register bank access */
static DEFINE_SPINLOCK(udc_lock);
@@ -498,8 +500,6 @@
hw_cwrite(CAP_ENDPTPRIME, BIT(n), BIT(n));
- while (hw_cread(CAP_ENDPTPRIME, BIT(n)))
- cpu_relax();
if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num)))
return -EAGAIN;
@@ -1006,6 +1006,44 @@
}
/**
+ * dbg_prime_fail: prints a PRIME FAIL event
+ * @addr: endpoint address
+ * @mEp: endpoint structure
+ */
+static void dbg_prime_fail(u8 addr, const char *name,
+ const struct ci13xxx_ep *mEp)
+{
+ char msg[DBG_DATA_MSG];
+ struct ci13xxx_req *req;
+ struct list_head *ptr = NULL;
+
+ if (mEp != NULL) {
+ scnprintf(msg, sizeof(msg),
+ "PRIME fail EP%d%s QH:%08X",
+ mEp->num, mEp->dir ? "IN" : "OUT", mEp->qh.ptr->cap);
+ dbg_print(addr, name, 0, msg);
+ scnprintf(msg, sizeof(msg),
+ "cap:%08X %08X %08X\n",
+ mEp->qh.ptr->curr, mEp->qh.ptr->td.next,
+ mEp->qh.ptr->td.token);
+ dbg_print(addr, "QHEAD", 0, msg);
+
+ list_for_each(ptr, &mEp->qh.queue) {
+ req = list_entry(ptr, struct ci13xxx_req, queue);
+ scnprintf(msg, sizeof(msg),
+ "%08X:%08X:%08X\n",
+ req->dma, req->ptr->next,
+ req->ptr->token);
+ dbg_print(addr, "REQ", 0, msg);
+ scnprintf(msg, sizeof(msg), "%08X:%d\n",
+ req->ptr->page[0],
+ req->req.status);
+ dbg_print(addr, "REQPAGE", 0, msg);
+ }
+ }
+}
+
+/**
* show_events: displays the event buffer
*
* Check "device.h" for details
@@ -1468,12 +1506,14 @@
n = hw_ep_bit(mEp->num, mEp->dir);
pr_info("%s: prime:%08x stat:%08x ep#%d dir:%s"
"dTD_update_fail_count: %lu "
- "mEp->dTD_update_fail_count: %lu\n", __func__,
+ "mEp->dTD_update_fail_count: %lu"
+ "mEp->prime_fail_count: %lu\n", __func__,
hw_cread(CAP_ENDPTPRIME, ~0),
hw_cread(CAP_ENDPTSTAT, ~0),
mEp->num, mEp->dir ? "IN" : "OUT",
udc->dTD_update_fail_count,
- mEp->dTD_update_fail_count);
+ mEp->dTD_update_fail_count,
+ mEp->prime_fail_count);
pr_info("QH: cap:%08x cur:%08x next:%08x token:%08x\n",
mEp->qh.ptr->cap, mEp->qh.ptr->curr,
@@ -1661,6 +1701,57 @@
return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num;
}
+static void ep_prime_timer_func(unsigned long data)
+{
+ struct ci13xxx_ep *mEp = (struct ci13xxx_ep *)data;
+ struct ci13xxx_req *req;
+ struct list_head *ptr = NULL;
+ int n = hw_ep_bit(mEp->num, mEp->dir);
+ unsigned long flags;
+
+
+ spin_lock_irqsave(mEp->lock, flags);
+ if (!hw_cread(CAP_ENDPTPRIME, BIT(n)))
+ goto out;
+
+ if (list_empty(&mEp->qh.queue))
+ goto out;
+
+ req = list_entry(mEp->qh.queue.next, struct ci13xxx_req, queue);
+
+ mb();
+ if (!(TD_STATUS_ACTIVE & req->ptr->token))
+ goto out;
+
+ mEp->prime_timer_count++;
+ if (mEp->prime_timer_count == MAX_PRIME_CHECK_RETRY) {
+ mEp->prime_timer_count = 0;
+ pr_info("ep%d dir:%s QH:cap:%08x cur:%08x next:%08x tkn:%08x\n",
+ mEp->num, mEp->dir ? "IN" : "OUT",
+ mEp->qh.ptr->cap, mEp->qh.ptr->curr,
+ mEp->qh.ptr->td.next, mEp->qh.ptr->td.token);
+ list_for_each(ptr, &mEp->qh.queue) {
+ req = list_entry(ptr, struct ci13xxx_req, queue);
+ pr_info("\treq:%08xnext:%08xtkn:%08xpage0:%08xsts:%d\n",
+ req->dma, req->ptr->next,
+ req->ptr->token, req->ptr->page[0],
+ req->req.status);
+ }
+ dbg_prime_fail(0xFF, "PRIMEF", mEp);
+ mEp->prime_fail_count++;
+ } else {
+ mod_timer(&mEp->prime_timer, EP_PRIME_CHECK_DELAY);
+ }
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+ return;
+
+out:
+ mEp->prime_timer_count = 0;
+ spin_unlock_irqrestore(mEp->lock, flags);
+
+}
+
/**
* _hardware_queue: configures a request at hardware level
* @gadget: gadget
@@ -1852,6 +1943,8 @@
ret = hw_ep_prime(mEp->num, mEp->dir,
mEp->type == USB_ENDPOINT_XFER_CONTROL);
+ if (!ret)
+ mod_timer(&mEp->prime_timer, EP_PRIME_CHECK_DELAY);
done:
return ret;
}
@@ -2300,6 +2393,8 @@
if (list_empty(&mEp->qh.queue))
return 0;
+ del_timer(&mEp->prime_timer);
+ mEp->prime_timer_count = 0;
list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue,
queue) {
dequeue:
@@ -2650,6 +2745,8 @@
/* only internal SW should disable ctrl endpts */
+ del_timer(&mEp->prime_timer);
+ mEp->prime_timer_count = 0;
direction = mEp->dir;
do {
dbg_event(_usb_addr(mEp), "DISABLE", 0);
@@ -2962,6 +3059,8 @@
spin_lock_irqsave(mEp->lock, flags);
+ del_timer(&mEp->prime_timer);
+ mEp->prime_timer_count = 0;
dbg_event(_usb_addr(mEp), "FFLUSH", 0);
hw_ep_flush(mEp->num, mEp->dir);
@@ -3434,6 +3533,8 @@
for (i = 0; i < hw_ep_max; i++) {
struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
INIT_LIST_HEAD(&mEp->ep.ep_list);
+ setup_timer(&mEp->prime_timer, ep_prime_timer_func,
+ (unsigned long) mEp);
}
if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) {
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index d67ad7c..6b3cad8 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -108,6 +108,9 @@
struct device *device;
struct dma_pool *td_pool;
unsigned long dTD_update_fail_count;
+ unsigned long prime_fail_count;
+ int prime_timer_count;
+ struct timer_list prime_timer;
};
struct ci13xxx;
diff --git a/drivers/usb/gadget/f_accessory.c b/drivers/usb/gadget/f_accessory.c
index 0353848..42a6c43 100644
--- a/drivers/usb/gadget/f_accessory.c
+++ b/drivers/usb/gadget/f_accessory.c
@@ -33,6 +33,8 @@
#include <linux/device.h>
#include <linux/miscdevice.h>
+#include <linux/hid.h>
+#include <linux/hiddev.h>
#include <linux/usb.h>
#include <linux/usb/ch9.h>
#include <linux/usb/f_accessory.h>
@@ -49,6 +51,20 @@
#define TX_REQ_MAX 4
#define RX_REQ_MAX 2
+struct acc_hid_dev {
+ struct list_head list;
+ struct hid_device *hid;
+ struct acc_dev *dev;
+ /* accessory defined ID */
+ int id;
+ /* HID report descriptor */
+ u8 *report_desc;
+ /* length of HID report descriptor */
+ int report_desc_len;
+ /* number of bytes of report_desc we have received so far */
+ int report_desc_offset;
+};
+
struct acc_dev {
struct usb_function function;
struct usb_composite_dev *cdev;
@@ -89,7 +105,21 @@
wait_queue_head_t write_wq;
struct usb_request *rx_req[RX_REQ_MAX];
int rx_done;
- struct delayed_work work;
+
+ /* delayed work for handling ACCESSORY_START */
+ struct delayed_work start_work;
+
+ /* worker for registering and unregistering hid devices */
+ struct work_struct hid_work;
+
+ /* list of active HID devices */
+ struct list_head hid_list;
+
+ /* list of new HID devices to register */
+ struct list_head new_hid_list;
+
+ /* list of dead HID devices to unregister */
+ struct list_head dead_hid_list;
};
static struct usb_interface_descriptor acc_interface_desc = {
@@ -298,6 +328,160 @@
}
}
+static void acc_complete_set_hid_report_desc(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ struct acc_hid_dev *hid = req->context;
+ struct acc_dev *dev = hid->dev;
+ int length = req->actual;
+
+ if (req->status != 0) {
+ pr_err("acc_complete_set_hid_report_desc, err %d\n",
+ req->status);
+ return;
+ }
+
+ memcpy(hid->report_desc + hid->report_desc_offset, req->buf, length);
+ hid->report_desc_offset += length;
+ if (hid->report_desc_offset == hid->report_desc_len) {
+ /* After we have received the entire report descriptor
+ * we schedule work to initialize the HID device
+ */
+ schedule_work(&dev->hid_work);
+ }
+}
+
+static void acc_complete_send_hid_event(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ struct acc_hid_dev *hid = req->context;
+ int length = req->actual;
+
+ if (req->status != 0) {
+ pr_err("acc_complete_send_hid_event, err %d\n", req->status);
+ return;
+ }
+
+ hid_report_raw_event(hid->hid, HID_INPUT_REPORT, req->buf, length, 1);
+}
+
+static int acc_hid_parse(struct hid_device *hid)
+{
+ struct acc_hid_dev *hdev = hid->driver_data;
+
+ hid_parse_report(hid, hdev->report_desc, hdev->report_desc_len);
+ return 0;
+}
+
+static int acc_hid_start(struct hid_device *hid)
+{
+ return 0;
+}
+
+static void acc_hid_stop(struct hid_device *hid)
+{
+}
+
+static int acc_hid_open(struct hid_device *hid)
+{
+ return 0;
+}
+
+static void acc_hid_close(struct hid_device *hid)
+{
+}
+
+static struct hid_ll_driver acc_hid_ll_driver = {
+ .parse = acc_hid_parse,
+ .start = acc_hid_start,
+ .stop = acc_hid_stop,
+ .open = acc_hid_open,
+ .close = acc_hid_close,
+};
+
+static struct acc_hid_dev *acc_hid_new(struct acc_dev *dev,
+ int id, int desc_len)
+{
+ struct acc_hid_dev *hdev;
+
+ hdev = kzalloc(sizeof(*hdev), GFP_ATOMIC);
+ if (!hdev)
+ return NULL;
+ hdev->report_desc = kzalloc(desc_len, GFP_ATOMIC);
+ if (!hdev->report_desc) {
+ kfree(hdev);
+ return NULL;
+ }
+ hdev->dev = dev;
+ hdev->id = id;
+ hdev->report_desc_len = desc_len;
+
+ return hdev;
+}
+
+static struct acc_hid_dev *acc_hid_get(struct list_head *list, int id)
+{
+ struct acc_hid_dev *hid;
+
+ list_for_each_entry(hid, list, list) {
+ if (hid->id == id)
+ return hid;
+ }
+ return NULL;
+}
+
+static int acc_register_hid(struct acc_dev *dev, int id, int desc_length)
+{
+ struct acc_hid_dev *hid;
+ unsigned long flags;
+
+ /* report descriptor length must be > 0 */
+ if (desc_length <= 0)
+ return -EINVAL;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ /* replace HID if one already exists with this ID */
+ hid = acc_hid_get(&dev->hid_list, id);
+ if (!hid)
+ hid = acc_hid_get(&dev->new_hid_list, id);
+ if (hid)
+ list_move(&hid->list, &dev->dead_hid_list);
+
+ hid = acc_hid_new(dev, id, desc_length);
+ if (!hid) {
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return -ENOMEM;
+ }
+
+ list_add(&hid->list, &dev->new_hid_list);
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ /* schedule work to register the HID device */
+ schedule_work(&dev->hid_work);
+ return 0;
+}
+
+static int acc_unregister_hid(struct acc_dev *dev, int id)
+{
+ struct acc_hid_dev *hid;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ hid = acc_hid_get(&dev->hid_list, id);
+ if (!hid)
+ hid = acc_hid_get(&dev->new_hid_list, id);
+ if (!hid) {
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return -EINVAL;
+ }
+
+ list_move(&hid->list, &dev->dead_hid_list);
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ schedule_work(&dev->hid_work);
+ return 0;
+}
+
static int create_bulk_endpoints(struct acc_dev *dev,
struct usb_endpoint_descriptor *in_desc,
struct usb_endpoint_descriptor *out_desc)
@@ -355,7 +539,7 @@
return 0;
fail:
- printk(KERN_ERR "acc_bind() could not allocate requests\n");
+ pr_err("acc_bind() could not allocate requests\n");
while ((req = req_get(dev, &dev->tx_idle)))
acc_request_free(req, dev->ep_in);
for (i = 0; i < RX_REQ_MAX; i++)
@@ -544,7 +728,7 @@
return 0;
}
-/* file operations for /dev/acc_usb */
+/* file operations for /dev/usb_accessory */
static const struct file_operations acc_fops = {
.owner = THIS_MODULE,
.read = acc_read,
@@ -554,23 +738,47 @@
.release = acc_release,
};
+static int acc_hid_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ int ret;
+
+ ret = hid_parse(hdev);
+ if (ret)
+ return ret;
+ return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+}
+
static struct miscdevice acc_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "usb_accessory",
.fops = &acc_fops,
};
+static const struct hid_device_id acc_hid_table[] = {
+ { HID_USB_DEVICE(HID_ANY_ID, HID_ANY_ID) },
+ { }
+};
+
+static struct hid_driver acc_hid_driver = {
+ .name = "USB accessory",
+ .id_table = acc_hid_table,
+ .probe = acc_hid_probe,
+};
static int acc_ctrlrequest(struct usb_composite_dev *cdev,
const struct usb_ctrlrequest *ctrl)
{
struct acc_dev *dev = _acc_dev;
int value = -EOPNOTSUPP;
+ struct acc_hid_dev *hid;
+ int offset;
u8 b_requestType = ctrl->bRequestType;
u8 b_request = ctrl->bRequest;
u16 w_index = le16_to_cpu(ctrl->wIndex);
u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
+ unsigned long flags;
/*
printk(KERN_INFO "acc_ctrlrequest "
@@ -583,7 +791,7 @@
if (b_request == ACCESSORY_START) {
dev->start_requested = 1;
schedule_delayed_work(
- &dev->work, msecs_to_jiffies(10));
+ &dev->start_work, msecs_to_jiffies(10));
value = 0;
} else if (b_request == ACCESSORY_SEND_STRING) {
dev->string_index = w_index;
@@ -594,13 +802,45 @@
w_index == 0 && w_length == 0) {
dev->audio_mode = w_value;
value = 0;
+ } else if (b_request == ACCESSORY_REGISTER_HID) {
+ value = acc_register_hid(dev, w_value, w_index);
+ } else if (b_request == ACCESSORY_UNREGISTER_HID) {
+ value = acc_unregister_hid(dev, w_value);
+ } else if (b_request == ACCESSORY_SET_HID_REPORT_DESC) {
+ spin_lock_irqsave(&dev->lock, flags);
+ hid = acc_hid_get(&dev->new_hid_list, w_value);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ if (!hid) {
+ value = -EINVAL;
+ goto err;
+ }
+ offset = w_index;
+ if (offset != hid->report_desc_offset
+ || offset + w_length > hid->report_desc_len) {
+ value = -EINVAL;
+ goto err;
+ }
+ cdev->req->context = hid;
+ cdev->req->complete = acc_complete_set_hid_report_desc;
+ value = w_length;
+ } else if (b_request == ACCESSORY_SEND_HID_EVENT) {
+ spin_lock_irqsave(&dev->lock, flags);
+ hid = acc_hid_get(&dev->hid_list, w_value);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ if (!hid) {
+ value = -EINVAL;
+ goto err;
+ }
+ cdev->req->context = hid;
+ cdev->req->complete = acc_complete_send_hid_event;
+ value = w_length;
}
} else if (b_requestType == (USB_DIR_IN | USB_TYPE_VENDOR)) {
if (b_request == ACCESSORY_GET_PROTOCOL) {
*((u16 *)cdev->req->buf) = PROTOCOL_VERSION;
value = sizeof(u16);
- /* clear any string left over from a previous session */
+ /* clear strings left over from a previous session */
memset(dev->manufacturer, 0, sizeof(dev->manufacturer));
memset(dev->model, 0, sizeof(dev->model));
memset(dev->description, 0, sizeof(dev->description));
@@ -621,6 +861,7 @@
__func__);
}
+err:
if (value == -EOPNOTSUPP)
VDBG(cdev,
"unknown class-specific control req "
@@ -640,6 +881,10 @@
DBG(cdev, "acc_function_bind dev: %p\n", dev);
+ ret = hid_register_driver(&acc_hid_driver);
+ if (ret)
+ return ret;
+
dev->start_requested = 0;
/* allocate interface ID(s) */
@@ -669,6 +914,36 @@
}
static void
+kill_all_hid_devices(struct acc_dev *dev)
+{
+ struct acc_hid_dev *hid;
+ struct list_head *entry, *temp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ list_for_each_safe(entry, temp, &dev->hid_list) {
+ hid = list_entry(entry, struct acc_hid_dev, list);
+ list_del(&hid->list);
+ list_add(&hid->list, &dev->dead_hid_list);
+ }
+ list_for_each_safe(entry, temp, &dev->new_hid_list) {
+ hid = list_entry(entry, struct acc_hid_dev, list);
+ list_del(&hid->list);
+ list_add(&hid->list, &dev->dead_hid_list);
+ }
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ schedule_work(&dev->hid_work);
+}
+
+static void
+acc_hid_unbind(struct acc_dev *dev)
+{
+ hid_unregister_driver(&acc_hid_driver);
+ kill_all_hid_devices(dev);
+}
+
+static void
acc_function_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct acc_dev *dev = func_to_dev(f);
@@ -679,14 +954,104 @@
acc_request_free(req, dev->ep_in);
for (i = 0; i < RX_REQ_MAX; i++)
acc_request_free(dev->rx_req[i], dev->ep_out);
+
+ acc_hid_unbind(dev);
}
-static void acc_work(struct work_struct *data)
+static void acc_start_work(struct work_struct *data)
{
char *envp[2] = { "ACCESSORY=START", NULL };
kobject_uevent_env(&acc_device.this_device->kobj, KOBJ_CHANGE, envp);
}
+static int acc_hid_init(struct acc_hid_dev *hdev)
+{
+ struct hid_device *hid;
+ int ret;
+
+ hid = hid_allocate_device();
+ if (IS_ERR(hid))
+ return PTR_ERR(hid);
+
+ hid->ll_driver = &acc_hid_ll_driver;
+ hid->dev.parent = acc_device.this_device;
+
+ hid->bus = BUS_USB;
+ hid->vendor = HID_ANY_ID;
+ hid->product = HID_ANY_ID;
+ hid->driver_data = hdev;
+ ret = hid_add_device(hid);
+ if (ret) {
+ pr_err("can't add hid device: %d\n", ret);
+ hid_destroy_device(hid);
+ return ret;
+ }
+
+ hdev->hid = hid;
+ return 0;
+}
+
+static void acc_hid_delete(struct acc_hid_dev *hid)
+{
+ kfree(hid->report_desc);
+ kfree(hid);
+}
+
+static void acc_hid_work(struct work_struct *data)
+{
+ struct acc_dev *dev = _acc_dev;
+ struct list_head *entry, *temp;
+ struct acc_hid_dev *hid;
+ struct list_head new_list, dead_list;
+ unsigned long flags;
+
+ INIT_LIST_HEAD(&new_list);
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ /* copy hids that are ready for initialization to new_list */
+ list_for_each_safe(entry, temp, &dev->new_hid_list) {
+ hid = list_entry(entry, struct acc_hid_dev, list);
+ if (hid->report_desc_offset == hid->report_desc_len)
+ list_move(&hid->list, &new_list);
+ }
+
+ if (list_empty(&dev->dead_hid_list)) {
+ INIT_LIST_HEAD(&dead_list);
+ } else {
+ /* move all of dev->dead_hid_list to dead_list */
+ dead_list.prev = dev->dead_hid_list.prev;
+ dead_list.next = dev->dead_hid_list.next;
+ dead_list.next->prev = &dead_list;
+ dead_list.prev->next = &dead_list;
+ INIT_LIST_HEAD(&dev->dead_hid_list);
+ }
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ /* register new HID devices */
+ list_for_each_safe(entry, temp, &new_list) {
+ hid = list_entry(entry, struct acc_hid_dev, list);
+ if (acc_hid_init(hid)) {
+ pr_err("can't add HID device %p\n", hid);
+ acc_hid_delete(hid);
+ } else {
+ spin_lock_irqsave(&dev->lock, flags);
+ list_move(&hid->list, &dev->hid_list);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ }
+ }
+
+ /* remove dead HID devices */
+ list_for_each_safe(entry, temp, &dead_list) {
+ hid = list_entry(entry, struct acc_hid_dev, list);
+ list_del(&hid->list);
+ if (hid->hid)
+ hid_destroy_device(hid->hid);
+ acc_hid_delete(hid);
+ }
+}
+
static int acc_function_set_alt(struct usb_function *f,
unsigned intf, unsigned alt)
{
@@ -792,7 +1157,11 @@
init_waitqueue_head(&dev->write_wq);
atomic_set(&dev->open_excl, 0);
INIT_LIST_HEAD(&dev->tx_idle);
- INIT_DELAYED_WORK(&dev->work, acc_work);
+ INIT_LIST_HEAD(&dev->hid_list);
+ INIT_LIST_HEAD(&dev->new_hid_list);
+ INIT_LIST_HEAD(&dev->dead_hid_list);
+ INIT_DELAYED_WORK(&dev->start_work, acc_start_work);
+ INIT_WORK(&dev->hid_work, acc_hid_work);
/* _acc_dev must be set before calling usb_gadget_register_driver */
_acc_dev = dev;
@@ -805,10 +1174,16 @@
err:
kfree(dev);
- printk(KERN_ERR "USB accessory gadget driver failed to initialize\n");
+ pr_err("USB accessory gadget driver failed to initialize\n");
return ret;
}
+static void acc_disconnect(void)
+{
+ /* unregister all HID devices if USB is disconnected */
+ kill_all_hid_devices(_acc_dev);
+}
+
static void acc_cleanup(void)
{
misc_deregister(&acc_device);
diff --git a/drivers/usb/gadget/f_audio_source.c b/drivers/usb/gadget/f_audio_source.c
new file mode 100644
index 0000000..aae941e
--- /dev/null
+++ b/drivers/usb/gadget/f_audio_source.c
@@ -0,0 +1,832 @@
+/*
+ * Gadget Function Driver for USB audio source device
+ *
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/usb/audio.h>
+#include <linux/wait.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+
+#define SAMPLE_RATE 44100
+#define FRAMES_PER_MSEC (SAMPLE_RATE / 1000)
+
+#define IN_EP_MAX_PACKET_SIZE 256
+
+/* Number of requests to allocate */
+#define IN_EP_REQ_COUNT 4
+
+#define AUDIO_AC_INTERFACE 0
+#define AUDIO_AS_INTERFACE 1
+#define AUDIO_NUM_INTERFACES 2
+
+/* B.3.1 Standard AC Interface Descriptor */
+static struct usb_interface_descriptor audio_source_ac_interface_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
+};
+
+
+#define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(AUDIO_NUM_INTERFACES)
+/* 1 input terminal, 1 output terminal and 1 feature unit */
+#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH \
+ + UAC_DT_INPUT_TERMINAL_SIZE + UAC_DT_OUTPUT_TERMINAL_SIZE \
+ + UAC_DT_FEATURE_UNIT_SIZE(0))
+/* B.3.2 Class-Specific AC Interface Descriptor */
+static struct uac1_ac_header_descriptor_2 audio_source_ac_header_desc = {
+ .bLength = UAC_DT_AC_HEADER_LENGTH,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_HEADER,
+ .bcdADC = __constant_cpu_to_le16(0x0100),
+ .wTotalLength = __constant_cpu_to_le16(UAC_DT_TOTAL_LENGTH),
+ .bInCollection = AUDIO_NUM_INTERFACES,
+ .baInterfaceNr = {
+ [0] = AUDIO_AC_INTERFACE,
+ [1] = AUDIO_AS_INTERFACE,
+ }
+};
+
+#define INPUT_TERMINAL_ID 1
+static struct uac_input_terminal_descriptor input_terminal_desc = {
+ .bLength = UAC_DT_INPUT_TERMINAL_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_INPUT_TERMINAL,
+ .bTerminalID = INPUT_TERMINAL_ID,
+ .wTerminalType = UAC_INPUT_TERMINAL_MICROPHONE,
+ .bAssocTerminal = 0,
+ .wChannelConfig = 0x3,
+};
+
+DECLARE_UAC_FEATURE_UNIT_DESCRIPTOR(0);
+
+#define FEATURE_UNIT_ID 2
+static struct uac_feature_unit_descriptor_0 feature_unit_desc = {
+ .bLength = UAC_DT_FEATURE_UNIT_SIZE(0),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_FEATURE_UNIT,
+ .bUnitID = FEATURE_UNIT_ID,
+ .bSourceID = INPUT_TERMINAL_ID,
+ .bControlSize = 2,
+};
+
+#define OUTPUT_TERMINAL_ID 3
+static struct uac1_output_terminal_descriptor output_terminal_desc = {
+ .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
+ .bTerminalID = OUTPUT_TERMINAL_ID,
+ .wTerminalType = UAC_TERMINAL_STREAMING,
+ .bAssocTerminal = FEATURE_UNIT_ID,
+ .bSourceID = FEATURE_UNIT_ID,
+};
+
+/* B.4.1 Standard AS Interface Descriptor */
+static struct usb_interface_descriptor as_interface_alt_0_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
+};
+
+static struct usb_interface_descriptor as_interface_alt_1_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bAlternateSetting = 1,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
+};
+
+/* B.4.2 Class-Specific AS Interface Descriptor */
+static struct uac1_as_header_descriptor as_header_desc = {
+ .bLength = UAC_DT_AS_HEADER_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_AS_GENERAL,
+ .bTerminalLink = INPUT_TERMINAL_ID,
+ .bDelay = 1,
+ .wFormatTag = UAC_FORMAT_TYPE_I_PCM,
+};
+
+static struct uac_format_type_i_discrete_descriptor_1 as_type_i_desc = {
+ .bLength = UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_FORMAT_TYPE,
+ .bFormatType = UAC_FORMAT_TYPE_I,
+ .bSubframeSize = 2,
+ .bBitResolution = 16,
+ .bSamFreqType = 1,
+};
+
+/* Standard ISO IN Endpoint Descriptor for highspeed */
+static struct usb_endpoint_descriptor hs_as_in_ep_desc = {
+ .bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_SYNC_SYNC
+ | USB_ENDPOINT_XFER_ISOC,
+ .wMaxPacketSize = __constant_cpu_to_le16(IN_EP_MAX_PACKET_SIZE),
+ .bInterval = 4, /* poll 1 per millisecond */
+};
+
+/* Standard ISO IN Endpoint Descriptor for highspeed */
+static struct usb_endpoint_descriptor fs_as_in_ep_desc = {
+ .bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_SYNC_SYNC
+ | USB_ENDPOINT_XFER_ISOC,
+ .wMaxPacketSize = __constant_cpu_to_le16(IN_EP_MAX_PACKET_SIZE),
+ .bInterval = 1, /* poll 1 per millisecond */
+};
+
+/* Class-specific AS ISO OUT Endpoint Descriptor */
+static struct uac_iso_endpoint_descriptor as_iso_in_desc = {
+ .bLength = UAC_ISO_ENDPOINT_DESC_SIZE,
+ .bDescriptorType = USB_DT_CS_ENDPOINT,
+ .bDescriptorSubtype = UAC_EP_GENERAL,
+ .bmAttributes = 1,
+ .bLockDelayUnits = 1,
+ .wLockDelay = __constant_cpu_to_le16(1),
+};
+
+static struct usb_descriptor_header *hs_audio_desc[] = {
+ (struct usb_descriptor_header *)&audio_source_ac_interface_desc,
+ (struct usb_descriptor_header *)&audio_source_ac_header_desc,
+
+ (struct usb_descriptor_header *)&input_terminal_desc,
+ (struct usb_descriptor_header *)&output_terminal_desc,
+ (struct usb_descriptor_header *)&feature_unit_desc,
+
+ (struct usb_descriptor_header *)&as_interface_alt_0_desc,
+ (struct usb_descriptor_header *)&as_interface_alt_1_desc,
+ (struct usb_descriptor_header *)&as_header_desc,
+
+ (struct usb_descriptor_header *)&as_type_i_desc,
+
+ (struct usb_descriptor_header *)&hs_as_in_ep_desc,
+ (struct usb_descriptor_header *)&as_iso_in_desc,
+ NULL,
+};
+
+static struct usb_descriptor_header *fs_audio_desc[] = {
+ (struct usb_descriptor_header *)&audio_source_ac_interface_desc,
+ (struct usb_descriptor_header *)&audio_source_ac_header_desc,
+
+ (struct usb_descriptor_header *)&input_terminal_desc,
+ (struct usb_descriptor_header *)&output_terminal_desc,
+ (struct usb_descriptor_header *)&feature_unit_desc,
+
+ (struct usb_descriptor_header *)&as_interface_alt_0_desc,
+ (struct usb_descriptor_header *)&as_interface_alt_1_desc,
+ (struct usb_descriptor_header *)&as_header_desc,
+
+ (struct usb_descriptor_header *)&as_type_i_desc,
+
+ (struct usb_descriptor_header *)&fs_as_in_ep_desc,
+ (struct usb_descriptor_header *)&as_iso_in_desc,
+ NULL,
+};
+
+static struct snd_pcm_hardware audio_hw_info = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER,
+
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = SAMPLE_RATE,
+ .rate_max = SAMPLE_RATE,
+
+ .buffer_bytes_max = 1024 * 1024,
+ .period_bytes_min = 64,
+ .period_bytes_max = 512 * 1024,
+ .periods_min = 2,
+ .periods_max = 1024,
+};
+
+/*-------------------------------------------------------------------------*/
+
+struct audio_source_config {
+ int card;
+ int device;
+};
+
+struct audio_dev {
+ struct usb_function func;
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+ struct snd_pcm_substream *substream;
+
+ struct list_head idle_reqs;
+ struct usb_ep *in_ep;
+
+ spinlock_t lock;
+
+ /* beginning, end and current position in our buffer */
+ void *buffer_start;
+ void *buffer_end;
+ void *buffer_pos;
+
+ /* byte size of a "period" */
+ unsigned int period;
+ /* bytes sent since last call to snd_pcm_period_elapsed */
+ unsigned int period_offset;
+ /* time we started playing */
+ ktime_t start_time;
+ /* number of frames sent since start_time */
+ s64 frames_sent;
+};
+
+static inline struct audio_dev *func_to_audio_source(struct usb_function *f)
+{
+ return container_of(f, struct audio_dev, func);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_request *audio_request_new(struct usb_ep *ep, int buffer_size)
+{
+ struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL);
+ if (!req)
+ return NULL;
+
+ req->buf = kmalloc(buffer_size, GFP_KERNEL);
+ if (!req->buf) {
+ usb_ep_free_request(ep, req);
+ return NULL;
+ }
+ req->length = buffer_size;
+ return req;
+}
+
+static void audio_request_free(struct usb_request *req, struct usb_ep *ep)
+{
+ if (req) {
+ kfree(req->buf);
+ usb_ep_free_request(ep, req);
+ }
+}
+
+static void audio_req_put(struct audio_dev *audio, struct usb_request *req)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->lock, flags);
+ list_add_tail(&req->list, &audio->idle_reqs);
+ spin_unlock_irqrestore(&audio->lock, flags);
+}
+
+static struct usb_request *audio_req_get(struct audio_dev *audio)
+{
+ unsigned long flags;
+ struct usb_request *req;
+
+ spin_lock_irqsave(&audio->lock, flags);
+ if (list_empty(&audio->idle_reqs)) {
+ req = 0;
+ } else {
+ req = list_first_entry(&audio->idle_reqs, struct usb_request,
+ list);
+ list_del(&req->list);
+ }
+ spin_unlock_irqrestore(&audio->lock, flags);
+ return req;
+}
+
+/* send the appropriate number of packets to match our bitrate */
+static void audio_send(struct audio_dev *audio)
+{
+ struct snd_pcm_runtime *runtime;
+ struct usb_request *req;
+ int length, length1, length2, ret;
+ s64 msecs;
+ s64 frames;
+ ktime_t now;
+
+ /* audio->substream will be null if we have been closed */
+ if (!audio->substream)
+ return;
+ /* audio->buffer_pos will be null if we have been stopped */
+ if (!audio->buffer_pos)
+ return;
+
+ runtime = audio->substream->runtime;
+
+ /* compute number of frames to send */
+ now = ktime_get();
+ msecs = ktime_to_ns(now) - ktime_to_ns(audio->start_time);
+ do_div(msecs, 1000000);
+ frames = msecs * SAMPLE_RATE;
+ do_div(frames, 1000);
+
+ /* Readjust our frames_sent if we fall too far behind.
+ * If we get too far behind it is better to drop some frames than
+ * to keep sending data too fast in an attempt to catch up.
+ */
+ if (frames - audio->frames_sent > 10 * FRAMES_PER_MSEC)
+ audio->frames_sent = frames - FRAMES_PER_MSEC;
+
+ frames -= audio->frames_sent;
+
+ /* We need to send something to keep the pipeline going */
+ if (frames <= 0)
+ frames = FRAMES_PER_MSEC;
+
+ while (frames > 0) {
+ req = audio_req_get(audio);
+ if (!req)
+ break;
+
+ length = frames_to_bytes(runtime, frames);
+ if (length > IN_EP_MAX_PACKET_SIZE)
+ length = IN_EP_MAX_PACKET_SIZE;
+
+ if (audio->buffer_pos + length > audio->buffer_end)
+ length1 = audio->buffer_end - audio->buffer_pos;
+ else
+ length1 = length;
+ memcpy(req->buf, audio->buffer_pos, length1);
+ if (length1 < length) {
+ /* Wrap around and copy remaining length
+ * at beginning of buffer.
+ */
+ length2 = length - length1;
+ memcpy(req->buf + length1, audio->buffer_start,
+ length2);
+ audio->buffer_pos = audio->buffer_start + length2;
+ } else {
+ audio->buffer_pos += length1;
+ if (audio->buffer_pos >= audio->buffer_end)
+ audio->buffer_pos = audio->buffer_start;
+ }
+
+ req->length = length;
+ ret = usb_ep_queue(audio->in_ep, req, GFP_ATOMIC);
+ if (ret < 0) {
+ pr_err("usb_ep_queue failed ret: %d\n", ret);
+ audio_req_put(audio, req);
+ break;
+ }
+
+ frames -= bytes_to_frames(runtime, length);
+ audio->frames_sent += bytes_to_frames(runtime, length);
+ }
+}
+
+static void audio_control_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ /* nothing to do here */
+}
+
+static void audio_data_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct audio_dev *audio = req->context;
+
+ pr_debug("audio_data_complete req->status %d req->actual %d\n",
+ req->status, req->actual);
+
+ audio_req_put(audio, req);
+
+ if (!audio->buffer_start || req->status)
+ return;
+
+ audio->period_offset += req->actual;
+ if (audio->period_offset >= audio->period) {
+ snd_pcm_period_elapsed(audio->substream);
+ audio->period_offset = 0;
+ }
+ audio_send(audio);
+}
+
+static int audio_source_set_endpoint_req(struct usb_function *f,
+ const struct usb_ctrlrequest *ctrl)
+{
+ int value = -EOPNOTSUPP;
+ u16 ep = le16_to_cpu(ctrl->wIndex);
+ u16 len = le16_to_cpu(ctrl->wLength);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+
+ pr_debug("bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
+ ctrl->bRequest, w_value, len, ep);
+
+ switch (ctrl->bRequest) {
+ case UAC_SET_CUR:
+ case UAC_SET_MIN:
+ case UAC_SET_MAX:
+ case UAC_SET_RES:
+ value = len;
+ break;
+ default:
+ break;
+ }
+
+ return value;
+}
+
+static int audio_source_get_endpoint_req(struct usb_function *f,
+ const struct usb_ctrlrequest *ctrl)
+{
+ struct usb_composite_dev *cdev = f->config->cdev;
+ int value = -EOPNOTSUPP;
+ u8 ep = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF);
+ u16 len = le16_to_cpu(ctrl->wLength);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u8 *buf = cdev->req->buf;
+
+ pr_debug("bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
+ ctrl->bRequest, w_value, len, ep);
+
+ if (w_value == UAC_EP_CS_ATTR_SAMPLE_RATE << 8) {
+ switch (ctrl->bRequest) {
+ case UAC_GET_CUR:
+ case UAC_GET_MIN:
+ case UAC_GET_MAX:
+ case UAC_GET_RES:
+ /* return our sample rate */
+ buf[0] = (u8)SAMPLE_RATE;
+ buf[1] = (u8)(SAMPLE_RATE >> 8);
+ buf[2] = (u8)(SAMPLE_RATE >> 16);
+ value = 3;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return value;
+}
+
+static int
+audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+{
+ struct usb_composite_dev *cdev = f->config->cdev;
+ struct usb_request *req = cdev->req;
+ int value = -EOPNOTSUPP;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
+
+ /* composite driver infrastructure handles everything; interface
+ * activation uses set_alt().
+ */
+ switch (ctrl->bRequestType) {
+ case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
+ value = audio_source_set_endpoint_req(f, ctrl);
+ break;
+
+ case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
+ value = audio_source_get_endpoint_req(f, ctrl);
+ break;
+ }
+
+ /* respond with data transfer or status phase? */
+ if (value >= 0) {
+ pr_debug("audio req%02x.%02x v%04x i%04x l%d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ w_value, w_index, w_length);
+ req->zero = 0;
+ req->length = value;
+ req->complete = audio_control_complete;
+ value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+ if (value < 0)
+ pr_err("audio response on err %d\n", value);
+ }
+
+ /* device either stalls (value < 0) or reports success */
+ return value;
+}
+
+static int audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+ struct audio_dev *audio = func_to_audio_source(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
+ int ret;
+
+ pr_debug("audio_set_alt intf %d, alt %d\n", intf, alt);
+
+ ret = config_ep_by_speed(cdev->gadget, f, audio->in_ep);
+ if (ret) {
+ audio->in_ep->desc = NULL;
+ ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+ audio->in_ep->name, ret);
+ return ret;
+ }
+ ret = usb_ep_enable(audio->in_ep);
+ if (ret) {
+ ERROR(cdev, "failed to enable ep %s, result %d\n",
+ audio->in_ep->name, ret);
+ return ret;
+ }
+ return 0;
+}
+
+static void audio_disable(struct usb_function *f)
+{
+ struct audio_dev *audio = func_to_audio_source(f);
+
+ pr_debug("audio_disable\n");
+ usb_ep_disable(audio->in_ep);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void audio_build_desc(struct audio_dev *audio)
+{
+ u8 *sam_freq;
+ int rate;
+
+ /* Set channel numbers */
+ input_terminal_desc.bNrChannels = 2;
+ as_type_i_desc.bNrChannels = 2;
+
+ /* Set sample rates */
+ rate = SAMPLE_RATE;
+ sam_freq = as_type_i_desc.tSamFreq[0];
+ memcpy(sam_freq, &rate, 3);
+}
+
+/* audio function driver setup/binding */
+static int
+audio_bind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct usb_composite_dev *cdev = c->cdev;
+ struct audio_dev *audio = func_to_audio_source(f);
+ int status;
+ struct usb_ep *ep;
+ struct usb_request *req;
+ int i;
+
+ audio_build_desc(audio);
+
+ /* allocate instance-specific interface IDs, and patch descriptors */
+ status = usb_interface_id(c, f);
+ if (status < 0)
+ goto fail;
+ audio_source_ac_interface_desc.bInterfaceNumber = status;
+
+ status = usb_interface_id(c, f);
+ if (status < 0)
+ goto fail;
+ as_interface_alt_0_desc.bInterfaceNumber = status;
+ as_interface_alt_1_desc.bInterfaceNumber = status;
+
+ status = -ENODEV;
+
+ /* allocate our endpoint */
+ ep = usb_ep_autoconfig(cdev->gadget, &fs_as_in_ep_desc);
+ if (!ep)
+ goto fail;
+ audio->in_ep = ep;
+ ep->driver_data = audio; /* claim */
+
+ if (gadget_is_dualspeed(c->cdev->gadget))
+ hs_as_in_ep_desc.bEndpointAddress =
+ fs_as_in_ep_desc.bEndpointAddress;
+
+ for (i = 0, status = 0; i < IN_EP_REQ_COUNT && status == 0; i++) {
+ req = audio_request_new(ep, IN_EP_MAX_PACKET_SIZE);
+ if (req) {
+ req->context = audio;
+ req->complete = audio_data_complete;
+ audio_req_put(audio, req);
+ } else
+ status = -ENOMEM;
+ }
+
+fail:
+ return status;
+}
+
+static void
+audio_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct audio_dev *audio = func_to_audio_source(f);
+ struct usb_request *req;
+
+ while ((req = audio_req_get(audio)))
+ audio_request_free(req, audio->in_ep);
+
+ snd_card_free_when_closed(audio->card);
+ audio->card = NULL;
+ audio->pcm = NULL;
+ audio->substream = NULL;
+ audio->in_ep = NULL;
+}
+
+static void audio_pcm_playback_start(struct audio_dev *audio)
+{
+ audio->start_time = ktime_get();
+ audio->frames_sent = 0;
+ audio_send(audio);
+}
+
+static void audio_pcm_playback_stop(struct audio_dev *audio)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->lock, flags);
+ audio->buffer_start = 0;
+ audio->buffer_end = 0;
+ audio->buffer_pos = 0;
+ spin_unlock_irqrestore(&audio->lock, flags);
+}
+
+static int audio_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct audio_dev *audio = substream->private_data;
+
+ runtime->private_data = audio;
+ runtime->hw = audio_hw_info;
+ snd_pcm_limit_hw_rates(runtime);
+ runtime->hw.channels_max = 2;
+
+ audio->substream = substream;
+ return 0;
+}
+
+static int audio_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct audio_dev *audio = substream->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->lock, flags);
+ audio->substream = NULL;
+ spin_unlock_irqrestore(&audio->lock, flags);
+
+ return 0;
+}
+
+static int audio_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ unsigned int channels = params_channels(params);
+ unsigned int rate = params_rate(params);
+
+ if (rate != SAMPLE_RATE)
+ return -EINVAL;
+ if (channels != 2)
+ return -EINVAL;
+
+ return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(params));
+}
+
+static int audio_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int audio_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct audio_dev *audio = runtime->private_data;
+
+ audio->period = snd_pcm_lib_period_bytes(substream);
+ audio->period_offset = 0;
+ audio->buffer_start = runtime->dma_area;
+ audio->buffer_end = audio->buffer_start
+ + snd_pcm_lib_buffer_bytes(substream);
+ audio->buffer_pos = audio->buffer_start;
+
+ return 0;
+}
+
+static snd_pcm_uframes_t audio_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct audio_dev *audio = runtime->private_data;
+ ssize_t bytes = audio->buffer_pos - audio->buffer_start;
+
+ /* return offset of next frame to fill in our buffer */
+ return bytes_to_frames(runtime, bytes);
+}
+
+static int audio_pcm_playback_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ struct audio_dev *audio = substream->runtime->private_data;
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ audio_pcm_playback_start(audio);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ audio_pcm_playback_stop(audio);
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static struct audio_dev _audio_dev = {
+ .func = {
+ .name = "audio_source",
+ .bind = audio_bind,
+ .unbind = audio_unbind,
+ .set_alt = audio_set_alt,
+ .setup = audio_setup,
+ .disable = audio_disable,
+ .descriptors = fs_audio_desc,
+ .hs_descriptors = hs_audio_desc,
+ },
+ .lock = __SPIN_LOCK_UNLOCKED(_audio_dev.lock),
+ .idle_reqs = LIST_HEAD_INIT(_audio_dev.idle_reqs),
+};
+
+static struct snd_pcm_ops audio_playback_ops = {
+ .open = audio_pcm_open,
+ .close = audio_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = audio_pcm_hw_params,
+ .hw_free = audio_pcm_hw_free,
+ .prepare = audio_pcm_prepare,
+ .trigger = audio_pcm_playback_trigger,
+ .pointer = audio_pcm_pointer,
+};
+
+int audio_source_bind_config(struct usb_configuration *c,
+ struct audio_source_config *config)
+{
+ struct audio_dev *audio;
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+ int err;
+
+ config->card = -1;
+ config->device = -1;
+
+ audio = &_audio_dev;
+
+ err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, 0, &card);
+ if (err)
+ return err;
+
+ snd_card_set_dev(card, &c->cdev->gadget->dev);
+
+ err = snd_pcm_new(card, "USB audio source", 0, 1, 0, &pcm);
+ if (err)
+ goto pcm_fail;
+ pcm->private_data = audio;
+ pcm->info_flags = 0;
+ audio->pcm = pcm;
+
+ strlcpy(pcm->name, "USB gadget audio", sizeof(pcm->name));
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &audio_playback_ops);
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+ NULL, 0, 64 * 1024);
+
+ strlcpy(card->driver, "audio_source", sizeof(card->driver));
+ strlcpy(card->shortname, card->driver, sizeof(card->shortname));
+ strlcpy(card->longname, "USB accessory audio source",
+ sizeof(card->longname));
+
+ err = snd_card_register(card);
+ if (err)
+ goto register_fail;
+
+ err = usb_add_function(c, &audio->func);
+ if (err)
+ goto add_fail;
+
+ config->card = pcm->card->number;
+ config->device = pcm->device;
+ audio->card = card;
+ return 0;
+
+add_fail:
+register_fail:
+pcm_fail:
+ snd_card_free(audio->card);
+ return err;
+}
diff --git a/drivers/usb/gadget/f_uac1.c b/drivers/usb/gadget/f_uac1.c
index b385592..8c74381 100644
--- a/drivers/usb/gadget/f_uac1.c
+++ b/drivers/usb/gadget/f_uac1.c
@@ -62,8 +62,6 @@
static int generic_set_cmd(struct usb_audio_control *con, u8 cmd, int value);
static int generic_get_cmd(struct usb_audio_control *con, u8 cmd);
-DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
-DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(1);
#define SPEAKER_INPUT_TERMINAL_ID 3
#define SPEAKER_OUTPUT_TERMINAL_ID 4
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 80ebc4f..25c39f6 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -96,6 +96,8 @@
struct mdss_mdp_ctl *ctl;
struct mdss_mdp_wb *wb;
struct list_head overlay_list;
+ struct list_head pipes_used;
+ struct list_head pipes_cleanup;
};
int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num);
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 6fd642f..33028cb 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -241,7 +241,9 @@
unsigned long smp[MAX_PLANES];
struct mdss_mdp_data buffers[2];
- struct list_head list;
+ struct list_head used_list;
+ struct list_head cleanup_list;
+
struct mdp_overlay_pp_params pp_cfg;
};
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 5966989..d21a095 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -90,18 +90,34 @@
*bus_ib_quota = 0;
*clk_rate = 0;
- if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
- struct mdss_panel_info *pinfo = &mixer->ctl->mfd->panel_info;
- v_total = (pinfo->yres + pinfo->lcdc.v_back_porch +
- pinfo->lcdc.v_front_porch + pinfo->lcdc.v_pulse_width);
- v_active = pinfo->yres;
- } else if (mixer->rotator_mode) {
+ if (mixer->rotator_mode) {
pipe = mixer->stage_pipe[0]; /* rotator pipe */
v_total = pipe->flags & MDP_ROT_90 ? pipe->dst.w : pipe->dst.h;
v_active = v_total;
} else {
- v_total = mixer->height;
- v_active = v_total;
+ int is_writeback = false;
+ if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
+ struct mdss_panel_info *pinfo;
+ pinfo = &mixer->ctl->mfd->panel_info;
+ v_total = (pinfo->yres + pinfo->lcdc.v_back_porch +
+ pinfo->lcdc.v_front_porch +
+ pinfo->lcdc.v_pulse_width);
+ v_active = pinfo->yres;
+
+ if (pinfo->type == WRITEBACK_PANEL)
+ is_writeback = true;
+ } else {
+ v_total = mixer->height;
+ v_active = v_total;
+
+ is_writeback = true;
+ }
+ *clk_rate = mixer->width * v_total * fps;
+ if (is_writeback) {
+ /* perf for bus writeback */
+ *bus_ab_quota = fps * mixer->width * mixer->height * 3;
+ *bus_ib_quota = *bus_ab_quota;
+ }
}
for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) {
@@ -118,7 +134,7 @@
if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF)
quota = (quota / v_active) * v_total;
- else
+ else if (mixer->rotator_mode)
quota *= 2; /* bus read + write */
rate = pipe->dst.w;
@@ -344,6 +360,8 @@
mdss_mdp_mixer_free(mixer);
mdss_mdp_ctl_free(ctl);
+ mdss_mdp_ctl_perf_commit(MDSS_MDP_PERF_UPDATE_ALL);
+
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index f76b508..452ebdc 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -282,7 +282,7 @@
}
mutex_lock(&mfd->lock);
- list_add(&pipe->list, &mfd->overlay_list);
+ list_add(&pipe->used_list, &mfd->pipes_used);
mutex_unlock(&mfd->lock);
pipe->mixer = mixer;
pipe->mfd = mfd;
@@ -395,24 +395,31 @@
static int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl)
{
- int ret;
+ struct mdss_mdp_pipe *pipe, *tmp;
+ struct msm_fb_data_type *mfd = ctl->mfd;
+ int i, ret;
- if (ctl->mfd->kickoff_fnc)
- ret = ctl->mfd->kickoff_fnc(ctl);
+ if (mfd->kickoff_fnc)
+ ret = mfd->kickoff_fnc(ctl);
else
ret = mdss_mdp_display_commit(ctl, NULL);
if (IS_ERR_VALUE(ret))
return ret;
- pr_debug("freeing previous buffers\n");
+ mutex_lock(&mfd->lock);
+ list_for_each_entry_safe(pipe, tmp, &mfd->pipes_cleanup, cleanup_list) {
+ list_del(&pipe->cleanup_list);
+ for (i = 0; i < ARRAY_SIZE(pipe->buffers); i++)
+ mdss_mdp_overlay_free_buf(&pipe->buffers[i]);
- mutex_lock(&ctl->mfd->lock);
- if (!list_empty(&ctl->mfd->overlay_list)) {
- struct mdss_mdp_pipe *pipe;
+ mdss_mdp_pipe_destroy(pipe);
+ }
+
+ if (!list_empty(&mfd->pipes_used)) {
struct mdss_mdp_data *data;
int buf_ndx;
- list_for_each_entry(pipe, &ctl->mfd->overlay_list, list) {
+ list_for_each_entry(pipe, &mfd->pipes_used, used_list) {
buf_ndx = (pipe->play_cnt - 1) & 1; /* prev buffer */
data = &pipe->buffers[buf_ndx];
@@ -423,9 +430,7 @@
}
}
}
- mutex_unlock(&ctl->mfd->lock);
-
- pr_debug("done freeing previous buffers\n");
+ mutex_unlock(&mfd->lock);
return ret;
}
@@ -433,8 +438,7 @@
static int mdss_mdp_overlay_unset(struct msm_fb_data_type *mfd, int ndx)
{
struct mdss_mdp_pipe *pipe;
- struct mdss_mdp_pipe *cleanup_pipes[MDSS_MDP_MAX_SSPP];
- int i, ret = 0, clean_cnt = 0;
+ int i, ret = 0;
u32 pipe_ndx, unset_ndx = 0;
if (!mfd || !mfd->ctl)
@@ -460,28 +464,15 @@
if (pipe_ndx & ndx) {
unset_ndx |= pipe_ndx;
pipe = mdss_mdp_pipe_get_locked(pipe_ndx);
- if (pipe) {
- mutex_lock(&mfd->lock);
- list_del(&pipe->list);
- mutex_unlock(&mfd->lock);
- mdss_mdp_mixer_pipe_unstage(pipe);
- cleanup_pipes[clean_cnt++] = pipe;
- } else {
+ if (!pipe) {
pr_warn("unknown pipe ndx=%x\n", pipe_ndx);
+ continue;
}
- }
- }
-
- if (clean_cnt) {
- int j;
- ret = mdss_mdp_overlay_kickoff(mfd->ctl);
-
- for (i = 0; i < clean_cnt; i++) {
- pipe = cleanup_pipes[i];
- for (j = 0; j < ARRAY_SIZE(pipe->buffers); j++)
- mdss_mdp_overlay_free_buf(&pipe->buffers[i]);
-
- mdss_mdp_pipe_destroy(pipe);
+ mutex_lock(&mfd->lock);
+ list_del(&pipe->used_list);
+ list_add(&pipe->cleanup_list, &mfd->pipes_cleanup);
+ mutex_unlock(&mfd->lock);
+ mdss_mdp_mixer_pipe_unstage(pipe);
}
}
@@ -495,8 +486,8 @@
int cnt = 0;
mutex_lock(&mfd->lock);
- if (!list_empty(&mfd->overlay_list)) {
- list_for_each_entry(pipe, &mfd->overlay_list, list) {
+ if (!list_empty(&mfd->pipes_used)) {
+ list_for_each_entry(pipe, &mfd->pipes_used, used_list) {
if (pipe->ndx & MDSS_MDP_ROT_SESSION_MASK) {
struct mdss_mdp_rotator_session *rot;
rot = mdss_mdp_rotator_session_get(pipe->ndx);
@@ -513,6 +504,7 @@
if (unset_ndx) {
pr_debug("%d pipes need cleanup (%x)\n", cnt, unset_ndx);
mdss_mdp_overlay_unset(mfd, unset_ndx);
+ mdss_mdp_overlay_kickoff(mfd->ctl);
}
return 0;
@@ -603,7 +595,7 @@
ctl = pipe->mixer->ctl;
mdss_mdp_pipe_unlock(pipe);
- if (ret == 0 && !(pipe->flags & MDP_OV_PLAY_NOWAIT))
+ if ((ret == 0) && (mfd->panel_info.type == WRITEBACK_PANEL))
ret = mdss_mdp_overlay_kickoff(ctl);
return ret;
@@ -1039,7 +1031,9 @@
ret = -EFAULT;
}
break;
-
+ case MSMFB_OVERLAY_COMMIT:
+ ret = mdss_mdp_overlay_kickoff(mfd->ctl);
+ break;
default:
if (mfd->panel_info.type == WRITEBACK_PANEL)
ret = mdss_mdp_wb_ioctl_handler(mfd, cmd, argp);
@@ -1063,7 +1057,8 @@
if (mfd->panel_info.type == WRITEBACK_PANEL)
mfd->kickoff_fnc = mdss_mdp_wb_kickoff;
- INIT_LIST_HEAD(&mfd->overlay_list);
+ INIT_LIST_HEAD(&mfd->pipes_used);
+ INIT_LIST_HEAD(&mfd->pipes_cleanup);
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.h b/drivers/video/msm/mdss/mdss_mdp_rotator.h
index 1e4b81e0..eb5b47a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.h
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.h
@@ -17,7 +17,7 @@
#include "mdss_mdp.h"
-#define MDSS_MDP_ROT_SESSION_MASK 0x80000000
+#define MDSS_MDP_ROT_SESSION_MASK 0x40000000
struct mdss_mdp_rotator_session {
u32 session_id;
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index abcdeab..9a66ff9 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -2088,7 +2088,7 @@
ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block,
struct ext4_extent *ex)
{
- struct ext4_ext_cache cex;
+ struct ext4_ext_cache cex = {0, 0, 0};
int ret = 0;
if (ext4_ext_check_cache(inode, block, &cex)) {
diff --git a/include/linux/mfd/pm8xxx/pm8038.h b/include/linux/mfd/pm8xxx/pm8038.h
index 682abc8..574dab6 100644
--- a/include/linux/mfd/pm8xxx/pm8038.h
+++ b/include/linux/mfd/pm8xxx/pm8038.h
@@ -54,6 +54,7 @@
/* PMIC Interrupts */
#define PM8038_RTC_ALARM_IRQ PM8038_IRQ_BLOCK_BIT(4, 7)
+#define PM8038_BATT_ALARM_IRQ PM8921_IRQ_BLOCK_BIT(5, 6)
#define PM8038_PWRKEY_REL_IRQ PM8038_IRQ_BLOCK_BIT(6, 2)
#define PM8038_PWRKEY_PRESS_IRQ PM8038_IRQ_BLOCK_BIT(6, 3)
#define PM8038_KEYPAD_IRQ PM8038_IRQ_BLOCK_BIT(9, 2)
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index c306c75..421d758 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -15,6 +15,8 @@
#include <linux/interrupt.h>
#include <linux/pm_qos.h>
+#include <linux/platform_device.h>
+#include <linux/of_irq.h>
#define WCD9XXX_NUM_IRQ_REGS 3
@@ -44,83 +46,41 @@
enum {
- TABLA_IRQ_SLIMBUS = 0,
- TABLA_IRQ_MBHC_REMOVAL,
- TABLA_IRQ_MBHC_SHORT_TERM,
- TABLA_IRQ_MBHC_PRESS,
- TABLA_IRQ_MBHC_RELEASE,
- TABLA_IRQ_MBHC_POTENTIAL,
- TABLA_IRQ_MBHC_INSERTION,
- TABLA_IRQ_BG_PRECHARGE,
- TABLA_IRQ_PA1_STARTUP,
- TABLA_IRQ_PA2_STARTUP,
- TABLA_IRQ_PA3_STARTUP,
- TABLA_IRQ_PA4_STARTUP,
- TABLA_IRQ_PA5_STARTUP,
- TABLA_IRQ_MICBIAS1_PRECHARGE,
- TABLA_IRQ_MICBIAS2_PRECHARGE,
- TABLA_IRQ_MICBIAS3_PRECHARGE,
- TABLA_IRQ_HPH_PA_OCPL_FAULT,
- TABLA_IRQ_HPH_PA_OCPR_FAULT,
- TABLA_IRQ_EAR_PA_OCPL_FAULT,
- TABLA_IRQ_HPH_L_PA_STARTUP,
- TABLA_IRQ_HPH_R_PA_STARTUP,
- TABLA_IRQ_EAR_PA_STARTUP,
- TABLA_NUM_IRQS,
+ WCD9XXX_IRQ_SLIMBUS = 0,
+ WCD9XXX_IRQ_MBHC_REMOVAL,
+ WCD9XXX_IRQ_MBHC_SHORT_TERM,
+ WCD9XXX_IRQ_MBHC_PRESS,
+ WCD9XXX_IRQ_MBHC_RELEASE,
+ WCD9XXX_IRQ_MBHC_POTENTIAL,
+ WCD9XXX_IRQ_MBHC_INSERTION,
+ WCD9XXX_IRQ_BG_PRECHARGE,
+ WCD9XXX_IRQ_PA1_STARTUP,
+ WCD9XXX_IRQ_PA2_STARTUP,
+ WCD9XXX_IRQ_PA3_STARTUP,
+ WCD9XXX_IRQ_PA4_STARTUP,
+ WCD9XXX_IRQ_PA5_STARTUP,
+ WCD9XXX_IRQ_MICBIAS1_PRECHARGE,
+ WCD9XXX_IRQ_MICBIAS2_PRECHARGE,
+ WCD9XXX_IRQ_MICBIAS3_PRECHARGE,
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
+ WCD9XXX_IRQ_EAR_PA_OCPL_FAULT,
+ WCD9XXX_IRQ_HPH_L_PA_STARTUP,
+ WCD9XXX_IRQ_HPH_R_PA_STARTUP,
+ WCD9XXX_IRQ_EAR_PA_STARTUP,
+ WCD9XXX_NUM_IRQS,
};
enum {
- SITAR_IRQ_SLIMBUS = 0,
- SITAR_IRQ_MBHC_REMOVAL,
- SITAR_IRQ_MBHC_SHORT_TERM,
- SITAR_IRQ_MBHC_PRESS,
- SITAR_IRQ_MBHC_RELEASE,
- SITAR_IRQ_MBHC_POTENTIAL,
- SITAR_IRQ_MBHC_INSERTION,
- SITAR_IRQ_BG_PRECHARGE,
- SITAR_IRQ_PA1_STARTUP,
- SITAR_IRQ_PA2_STARTUP,
- SITAR_IRQ_PA3_STARTUP,
- SITAR_IRQ_PA4_STARTUP,
- SITAR_IRQ_PA5_STARTUP,
- SITAR_IRQ_MICBIAS1_PRECHARGE,
- SITAR_IRQ_MICBIAS2_PRECHARGE,
- SITAR_IRQ_MICBIAS3_PRECHARGE,
- SITAR_IRQ_HPH_PA_OCPL_FAULT,
- SITAR_IRQ_HPH_PA_OCPR_FAULT,
- SITAR_IRQ_EAR_PA_OCPL_FAULT,
- SITAR_IRQ_HPH_L_PA_STARTUP,
- SITAR_IRQ_HPH_R_PA_STARTUP,
- SITAR_IRQ_EAR_PA_STARTUP,
- SITAR_NUM_IRQS,
+ TABLA_NUM_IRQS = WCD9XXX_NUM_IRQS,
+ SITAR_NUM_IRQS = WCD9XXX_NUM_IRQS,
+ TAIKO_NUM_IRQS = WCD9XXX_NUM_IRQS,
};
-enum {
- TAIKO_IRQ_SLIMBUS = 0,
- TAIKO_IRQ_MBHC_REMOVAL,
- TAIKO_IRQ_MBHC_SHORT_TERM,
- TAIKO_IRQ_MBHC_PRESS,
- TAIKO_IRQ_MBHC_RELEASE,
- TAIKO_IRQ_MBHC_POTENTIAL,
- TAIKO_IRQ_MBHC_INSERTION,
- TAIKO_IRQ_BG_PRECHARGE,
- TAIKO_IRQ_PA1_STARTUP,
- TAIKO_IRQ_PA2_STARTUP,
- TAIKO_IRQ_PA3_STARTUP,
- TAIKO_IRQ_PA4_STARTUP,
- TAIKO_IRQ_PA5_STARTUP,
- TAIKO_IRQ_MICBIAS1_PRECHARGE,
- TAIKO_IRQ_MICBIAS2_PRECHARGE,
- TAIKO_IRQ_MICBIAS3_PRECHARGE,
- TAIKO_IRQ_HPH_PA_OCPL_FAULT,
- TAIKO_IRQ_HPH_PA_OCPR_FAULT,
- TAIKO_IRQ_EAR_PA_OCPL_FAULT,
- TAIKO_IRQ_HPH_L_PA_STARTUP,
- TAIKO_IRQ_HPH_R_PA_STARTUP,
- TAIKO_IRQ_EAR_PA_STARTUP,
- TAIKO_NUM_IRQS,
-};
+#define MAX(X, Y) (((int)X) >= ((int)Y) ? (X) : (Y))
+#define WCD9XXX_MAX_NUM_IRQS (MAX(MAX(TABLA_NUM_IRQS, SITAR_NUM_IRQS), \
+ TAIKO_NUM_IRQS))
enum wcd9xxx_pm_state {
WCD9XXX_PM_SLEEPABLE,
@@ -137,12 +97,6 @@
struct mutex irq_lock;
u8 version;
- unsigned int irq_base;
- unsigned int irq;
- u8 irq_masks_cur[WCD9XXX_NUM_IRQ_REGS];
- u8 irq_masks_cache[WCD9XXX_NUM_IRQ_REGS];
- u8 irq_level[WCD9XXX_NUM_IRQ_REGS];
-
int reset_gpio;
int (*read_dev)(struct wcd9xxx *wcd9xxx, unsigned short reg,
@@ -164,6 +118,13 @@
int num_tx_port;
u8 idbyte[4];
+
+ unsigned int irq_base;
+ unsigned int irq;
+ u8 irq_masks_cur[WCD9XXX_NUM_IRQ_REGS];
+ u8 irq_masks_cache[WCD9XXX_NUM_IRQ_REGS];
+ bool irq_level_high[WCD9XXX_MAX_NUM_IRQS];
+ int num_irqs;
};
int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
@@ -187,40 +148,15 @@
enum wcd9xxx_pm_state o,
enum wcd9xxx_pm_state n);
-static inline int wcd9xxx_request_irq(struct wcd9xxx *wcd9xxx, int irq,
- irq_handler_t handler, const char *name,
- void *data)
-{
- if (!wcd9xxx->irq_base)
- return -EINVAL;
- return request_threaded_irq(wcd9xxx->irq_base + irq, NULL, handler,
- IRQF_TRIGGER_RISING, name,
- data);
-}
-static inline void wcd9xxx_free_irq(struct wcd9xxx *wcd9xxx,
- int irq, void *data)
-{
- if (!wcd9xxx->irq_base)
- return;
- free_irq(wcd9xxx->irq_base + irq, data);
-}
-static inline void wcd9xxx_enable_irq(struct wcd9xxx *wcd9xxx, int irq)
-{
- if (!wcd9xxx->irq_base)
- return;
- enable_irq(wcd9xxx->irq_base + irq);
-}
-static inline void wcd9xxx_disable_irq(struct wcd9xxx *wcd9xxx, int irq)
-{
- if (!wcd9xxx->irq_base)
- return;
- disable_irq_nosync(wcd9xxx->irq_base + irq);
-}
-static inline void wcd9xxx_disable_irq_sync(struct wcd9xxx *wcd9xxx, int irq)
-{
- if (!wcd9xxx->irq_base)
- return;
- disable_irq(wcd9xxx->irq_base + irq);
-}
+int wcd9xxx_request_irq(struct wcd9xxx *wcd9xxx, int irq,
+ irq_handler_t handler, const char *name, void *data);
+void wcd9xxx_free_irq(struct wcd9xxx *wcd9xxx, int irq, void *data);
+void wcd9xxx_enable_irq(struct wcd9xxx *wcd9xxx, int irq);
+void wcd9xxx_disable_irq(struct wcd9xxx *wcd9xxx, int irq);
+void wcd9xxx_disable_irq_sync(struct wcd9xxx *wcd9xxx, int irq);
+#ifdef CONFIG_OF
+int __init wcd9xxx_irq_of_init(struct device_node *node,
+ struct device_node *parent);
+#endif /* CONFIG_OF */
#endif
diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h b/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
index c66e953..357f400 100644
--- a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
@@ -39,4 +39,12 @@
#define WCD9XXX_A_CDC_CTL__POR (0x00000000)
#define WCD9XXX_A_LEAKAGE_CTL (0x88)
#define WCD9XXX_A_LEAKAGE_CTL__POR (0x00000004)
+#define WCD9XXX_A_INTR_MODE (0x90)
+#define WCD9XXX_A_INTR_MASK0 (0x94)
+#define WCD9XXX_A_INTR_STATUS0 (0x98)
+#define WCD9XXX_A_INTR_CLEAR0 (0x9C)
+#define WCD9XXX_A_INTR_LEVEL0 (0xA0)
+#define WCD9XXX_A_INTR_LEVEL1 (0xA1)
+#define WCD9XXX_A_INTR_LEVEL2 (0xA2)
+
#endif
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 257bcc0..477733c 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -248,6 +248,7 @@
struct delayed_work dw;
unsigned int host_suspend_tout_ms;
unsigned int delay_ms;
+ unsigned int min_sectors_to_queue_delayed_work;
/*
* A default time for checking the need for non urgent BKOPS once mmcqd
* is idle.
diff --git a/include/linux/usb/audio.h b/include/linux/usb/audio.h
index a54b825..c3ea237 100644
--- a/include/linux/usb/audio.h
+++ b/include/linux/usb/audio.h
@@ -175,6 +175,7 @@
__u8 baInterfaceNr[n]; \
} __attribute__ ((packed))
+DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
/* 4.3.2.1 Input Terminal Descriptor */
struct uac_input_terminal_descriptor {
__u8 bLength; /* in bytes: 12 */
@@ -454,6 +455,7 @@
__u8 tSamFreq[n][3]; \
} __attribute__ ((packed))
+DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(1);
#define UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(n) (8 + (n * 3))
struct uac_format_type_i_ext_descriptor {
diff --git a/include/linux/usb/f_accessory.h b/include/linux/usb/f_accessory.h
index ddb2fd0..61ebe0a 100644
--- a/include/linux/usb/f_accessory.h
+++ b/include/linux/usb/f_accessory.h
@@ -44,7 +44,7 @@
* index: 0
* data version number (16 bits little endian)
* 1 for original accessory support
- * 2 adds device to host audio support
+ * 2 adds HID and device to host audio support
*/
#define ACCESSORY_GET_PROTOCOL 51
@@ -72,6 +72,54 @@
*/
#define ACCESSORY_START 53
+/* Control request for registering a HID device.
+ * Upon registering, a unique ID is sent by the accessory in the
+ * value parameter. This ID will be used for future commands for
+ * the device
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_REGISTER_HID_DEVICE
+ * value: Accessory assigned ID for the HID device
+ * index: total length of the HID report descriptor
+ * data none
+ */
+#define ACCESSORY_REGISTER_HID 54
+
+/* Control request for unregistering a HID device.
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_REGISTER_HID
+ * value: Accessory assigned ID for the HID device
+ * index: 0
+ * data none
+ */
+#define ACCESSORY_UNREGISTER_HID 55
+
+/* Control request for sending the HID report descriptor.
+ * If the HID descriptor is longer than the endpoint zero max packet size,
+ * the descriptor will be sent in multiple ACCESSORY_SET_HID_REPORT_DESC
+ * commands. The data for the descriptor must be sent sequentially
+ * if multiple packets are needed.
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_SET_HID_REPORT_DESC
+ * value: Accessory assigned ID for the HID device
+ * index: offset of data in descriptor
+ * (needed when HID descriptor is too big for one packet)
+ * data the HID report descriptor
+ */
+#define ACCESSORY_SET_HID_REPORT_DESC 56
+
+/* Control request for sending HID events.
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_SEND_HID_EVENT
+ * value: Accessory assigned ID for the HID device
+ * index: 0
+ * data the HID report for the event
+ */
+#define ACCESSORY_SEND_HID_EVENT 57
+
/* Control request for setting the audio mode.
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index e9e950f..fa7abb1 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -1713,7 +1713,7 @@
/* reset retry counter as PA is turned off signifying
* start of new OCP detection session
*/
- if (SITAR_IRQ_HPH_PA_OCPL_FAULT)
+ if (WCD9XXX_IRQ_HPH_PA_OCPL_FAULT)
sitar->hphlocp_cnt = 0;
else
sitar->hphrocp_cnt = 0;
@@ -1725,14 +1725,16 @@
{
struct sitar_priv *sitar = container_of(work, struct sitar_priv,
hphlocp_work);
- hphocp_off_report(sitar, SND_JACK_OC_HPHL, SITAR_IRQ_HPH_PA_OCPL_FAULT);
+ hphocp_off_report(sitar, SND_JACK_OC_HPHL,
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
}
static void hphrocp_off_report(struct work_struct *work)
{
struct sitar_priv *sitar = container_of(work, struct sitar_priv,
hphrocp_work);
- hphocp_off_report(sitar, SND_JACK_OC_HPHR, SITAR_IRQ_HPH_PA_OCPR_FAULT);
+ hphocp_off_report(sitar, SND_JACK_OC_HPHR,
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
}
static int sitar_hph_pa_event(struct snd_soc_dapm_widget *w,
@@ -3187,7 +3189,7 @@
short bias_value;
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
- wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
if (noreldetection)
sitar_turn_onoff_rel_detection(codec, false);
@@ -3223,7 +3225,7 @@
if (noreldetection)
sitar_turn_onoff_rel_detection(codec, true);
- wcd9xxx_enable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
return bias_value;
}
@@ -3441,7 +3443,7 @@
sitar = snd_soc_codec_get_drvdata(codec);
calibration = sitar->mbhc_cfg.calibration;
- wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
sitar_turn_onoff_rel_detection(codec, false);
/* First compute the DCE / STA wait times
@@ -3524,7 +3526,7 @@
snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
usleep_range(100, 100);
- wcd9xxx_enable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
sitar_turn_onoff_rel_detection(codec, true);
}
@@ -3808,9 +3810,9 @@
}
sitar_set_and_turnoff_hph_padac(codec);
hphocp_off_report(sitar, SND_JACK_OC_HPHR,
- SITAR_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
hphocp_off_report(sitar, SND_JACK_OC_HPHL,
- SITAR_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
sitar->current_plug = PLUG_TYPE_NONE;
sitar->mbhc_polling_active = false;
} else {
@@ -4232,9 +4234,9 @@
snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL,
0x10, 0x10);
wcd9xxx_enable_irq(codec->control_data,
- SITAR_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
wcd9xxx_enable_irq(codec->control_data,
- SITAR_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
/* Bootup time detection */
sitar_hs_gpio_handler(codec);
}
@@ -4624,7 +4626,7 @@
0x10);
} else {
wcd9xxx_disable_irq(codec->control_data,
- SITAR_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
sitar->hphlocp_cnt = 0;
sitar->hph_status |= SND_JACK_OC_HPHL;
if (sitar->mbhc_cfg.headset_jack)
@@ -4657,7 +4659,7 @@
0x10);
} else {
wcd9xxx_disable_irq(codec->control_data,
- SITAR_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
sitar->hphrocp_cnt = 0;
sitar->hph_status |= SND_JACK_OC_HPHR;
if (sitar->mbhc_cfg.headset_jack)
@@ -4680,7 +4682,7 @@
pr_debug("%s: enter\n", __func__);
SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
- wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
@@ -5136,44 +5138,49 @@
snd_soc_dapm_sync(dapm);
- ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION,
+ ret = wcd9xxx_request_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_INSERTION,
sitar_hs_insert_irq, "Headset insert detect", sitar);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- SITAR_IRQ_MBHC_INSERTION);
+ WCD9XXX_IRQ_MBHC_INSERTION);
goto err_insert_irq;
}
- wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
- ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL,
+ ret = wcd9xxx_request_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_REMOVAL,
sitar_hs_remove_irq, "Headset remove detect", sitar);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- SITAR_IRQ_MBHC_REMOVAL);
+ WCD9XXX_IRQ_MBHC_REMOVAL);
goto err_remove_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL,
+ ret = wcd9xxx_request_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_POTENTIAL,
sitar_dce_handler, "DC Estimation detect", sitar);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- SITAR_IRQ_MBHC_POTENTIAL);
+ WCD9XXX_IRQ_MBHC_POTENTIAL);
goto err_potential_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE,
- sitar_release_handler, "Button Release detect", sitar);
+ ret = wcd9xxx_request_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_RELEASE,
+ sitar_release_handler,
+ "Button Release detect", sitar);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- SITAR_IRQ_MBHC_RELEASE);
+ WCD9XXX_IRQ_MBHC_RELEASE);
goto err_release_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_SLIMBUS,
- sitar_slimbus_irq, "SLIMBUS Slave", sitar);
+ ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
+ sitar_slimbus_irq, "SLIMBUS Slave", sitar);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- SITAR_IRQ_SLIMBUS);
+ WCD9XXX_IRQ_SLIMBUS);
goto err_slimbus_irq;
}
@@ -5183,24 +5190,27 @@
ret = wcd9xxx_request_irq(codec->control_data,
- SITAR_IRQ_HPH_PA_OCPL_FAULT, sitar_hphl_ocp_irq,
- "HPH_L OCP detect", sitar);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
+ sitar_hphl_ocp_irq,
+ "HPH_L OCP detect", sitar);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- SITAR_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
goto err_hphl_ocp_irq;
}
- wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_HPH_PA_OCPL_FAULT);
+ wcd9xxx_disable_irq(codec->control_data,
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
ret = wcd9xxx_request_irq(codec->control_data,
- SITAR_IRQ_HPH_PA_OCPR_FAULT, sitar_hphr_ocp_irq,
- "HPH_R OCP detect", sitar);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
+ sitar_hphr_ocp_irq, "HPH_R OCP detect",
+ sitar);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- SITAR_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
goto err_hphr_ocp_irq;
}
- wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_HPH_PA_OCPR_FAULT);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
for (i = 0; i < ARRAY_SIZE(sitar_dai); i++) {
switch (sitar_dai[i].id) {
@@ -5227,23 +5237,20 @@
return ret;
err_hphr_ocp_irq:
- wcd9xxx_free_irq(codec->control_data,
- SITAR_IRQ_HPH_PA_OCPL_FAULT, sitar);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
+ sitar);
err_hphl_ocp_irq:
- wcd9xxx_free_irq(codec->control_data,
- SITAR_IRQ_SLIMBUS, sitar);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, sitar);
err_slimbus_irq:
- wcd9xxx_free_irq(codec->control_data,
- SITAR_IRQ_MBHC_RELEASE, sitar);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
err_release_irq:
- wcd9xxx_free_irq(codec->control_data,
- SITAR_IRQ_MBHC_POTENTIAL, sitar);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
+ sitar);
err_potential_irq:
- wcd9xxx_free_irq(codec->control_data,
- SITAR_IRQ_MBHC_REMOVAL, sitar);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
err_remove_irq:
- wcd9xxx_free_irq(codec->control_data,
- SITAR_IRQ_MBHC_INSERTION, sitar);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
+ sitar);
err_insert_irq:
err_pdata:
mutex_destroy(&sitar->codec_resource_lock);
@@ -5254,11 +5261,13 @@
{
int i;
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
- wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_SLIMBUS, sitar);
- wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE, sitar);
- wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL, sitar);
- wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL, sitar);
- wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION, sitar);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, sitar);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
+ sitar);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
+ sitar);
SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
sitar_codec_disable_clock_block(codec);
SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 5a819c9..b64a6a7 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -2911,7 +2911,7 @@
/* reset retry counter as PA is turned off signifying
* start of new OCP detection session
*/
- if (TABLA_IRQ_HPH_PA_OCPL_FAULT)
+ if (WCD9XXX_IRQ_HPH_PA_OCPL_FAULT)
tabla->hphlocp_cnt = 0;
else
tabla->hphrocp_cnt = 0;
@@ -2923,14 +2923,16 @@
{
struct tabla_priv *tabla = container_of(work, struct tabla_priv,
hphlocp_work);
- hphocp_off_report(tabla, SND_JACK_OC_HPHL, TABLA_IRQ_HPH_PA_OCPL_FAULT);
+ hphocp_off_report(tabla, SND_JACK_OC_HPHL,
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
}
static void hphrocp_off_report(struct work_struct *work)
{
struct tabla_priv *tabla = container_of(work, struct tabla_priv,
hphrocp_work);
- hphocp_off_report(tabla, SND_JACK_OC_HPHR, TABLA_IRQ_HPH_PA_OCPR_FAULT);
+ hphocp_off_report(tabla, SND_JACK_OC_HPHR,
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
}
static int tabla_hph_pa_event(struct snd_soc_dapm_widget *w,
@@ -5120,7 +5122,7 @@
short bias_value;
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
- wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
if (noreldetection)
tabla_turn_onoff_rel_detection(codec, false);
@@ -5156,7 +5158,7 @@
if (noreldetection)
tabla_turn_onoff_rel_detection(codec, true);
- wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
return bias_value;
}
@@ -5345,9 +5347,9 @@
}
tabla_set_and_turnoff_hph_padac(codec);
hphocp_off_report(tabla, SND_JACK_OC_HPHR,
- TABLA_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
hphocp_off_report(tabla, SND_JACK_OC_HPHL,
- TABLA_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
tabla->current_plug = PLUG_TYPE_NONE;
tabla->mbhc_polling_active = false;
} else {
@@ -5510,7 +5512,7 @@
snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x3,
tabla->mbhc_cfg.micbias);
- wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+ wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
pr_debug("%s: leave\n", __func__);
return 0;
@@ -5640,7 +5642,7 @@
tabla = snd_soc_codec_get_drvdata(codec);
calibration = tabla->mbhc_cfg.calibration;
- wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
tabla_turn_onoff_rel_detection(codec, false);
/* First compute the DCE / STA wait times
@@ -5746,7 +5748,7 @@
snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
usleep_range(100, 100);
- wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
tabla_turn_onoff_rel_detection(codec, true);
}
@@ -6334,7 +6336,7 @@
0x10);
} else {
wcd9xxx_disable_irq(codec->control_data,
- TABLA_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
tabla->hph_status |= SND_JACK_OC_HPHL;
if (tabla->mbhc_cfg.headset_jack)
tabla_snd_soc_jack_report(tabla,
@@ -6368,7 +6370,7 @@
0x10);
} else {
wcd9xxx_disable_irq(codec->control_data,
- TABLA_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
tabla->hph_status |= SND_JACK_OC_HPHR;
if (tabla->mbhc_cfg.headset_jack)
tabla_snd_soc_jack_report(tabla,
@@ -6977,7 +6979,7 @@
wcd9xxx_unlock_sleep(core);
} else {
wcd9xxx_enable_irq(codec->control_data,
- TABLA_IRQ_MBHC_INSERTION);
+ WCD9XXX_IRQ_MBHC_INSERTION);
pr_err("%s: Error detecting plug insertion\n",
__func__);
}
@@ -7015,7 +7017,7 @@
pr_debug("%s: enter\n", __func__);
TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
- wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
is_mb_trigger = !!(snd_soc_read(codec, priv->mbhc_bias_regs.mbhc_reg) &
0x10);
@@ -7262,7 +7264,8 @@
snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
- wcd9xxx_disable_irq_sync(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq_sync(codec->control_data,
+ WCD9XXX_IRQ_MBHC_INSERTION);
tabla_codec_detect_plug_type(codec);
wcd9xxx_unlock_sleep(tabla_core);
}
@@ -7485,9 +7488,9 @@
if (!IS_ERR_VALUE(ret)) {
snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
wcd9xxx_enable_irq(codec->control_data,
- TABLA_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
wcd9xxx_enable_irq(codec->control_data,
- TABLA_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
if (tabla->mbhc_cfg.gpio) {
ret = request_threaded_irq(tabla->mbhc_cfg.gpio_irq,
@@ -8218,44 +8221,50 @@
snd_soc_dapm_sync(dapm);
- ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
+ ret = wcd9xxx_request_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_INSERTION,
tabla_hs_insert_irq, "Headset insert detect", tabla);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TABLA_IRQ_MBHC_INSERTION);
+ WCD9XXX_IRQ_MBHC_INSERTION);
goto err_insert_irq;
}
- wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
- ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
- tabla_hs_remove_irq, "Headset remove detect", tabla);
+ ret = wcd9xxx_request_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_REMOVAL,
+ tabla_hs_remove_irq,
+ "Headset remove detect", tabla);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TABLA_IRQ_MBHC_REMOVAL);
+ WCD9XXX_IRQ_MBHC_REMOVAL);
goto err_remove_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
- tabla_dce_handler, "DC Estimation detect", tabla);
+ ret = wcd9xxx_request_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_POTENTIAL,
+ tabla_dce_handler, "DC Estimation detect",
+ tabla);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TABLA_IRQ_MBHC_POTENTIAL);
+ WCD9XXX_IRQ_MBHC_POTENTIAL);
goto err_potential_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
- tabla_release_handler, "Button Release detect", tabla);
+ ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE,
+ tabla_release_handler,
+ "Button Release detect", tabla);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TABLA_IRQ_MBHC_RELEASE);
+ WCD9XXX_IRQ_MBHC_RELEASE);
goto err_release_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
- tabla_slimbus_irq, "SLIMBUS Slave", tabla);
+ ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
+ tabla_slimbus_irq, "SLIMBUS Slave", tabla);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TABLA_IRQ_SLIMBUS);
+ WCD9XXX_IRQ_SLIMBUS);
goto err_slimbus_irq;
}
@@ -8264,24 +8273,26 @@
TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
ret = wcd9xxx_request_irq(codec->control_data,
- TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla_hphl_ocp_irq,
- "HPH_L OCP detect", tabla);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
+ tabla_hphl_ocp_irq,
+ "HPH_L OCP detect", tabla);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TABLA_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
goto err_hphl_ocp_irq;
}
- wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
ret = wcd9xxx_request_irq(codec->control_data,
- TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
- "HPH_R OCP detect", tabla);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
+ tabla_hphr_ocp_irq,
+ "HPH_R OCP detect", tabla);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TABLA_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
goto err_hphr_ocp_irq;
}
- wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
/*
* Register suspend lock and notifier to resend edge triggered
@@ -8334,17 +8345,19 @@
err_hphr_ocp_irq:
wcd9xxx_free_irq(codec->control_data,
- TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, tabla);
err_hphl_ocp_irq:
- wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, tabla);
err_slimbus_irq:
- wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, tabla);
err_release_irq:
- wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
+ tabla);
err_potential_irq:
- wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, tabla);
err_remove_irq:
- wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
+ tabla);
err_insert_irq:
err_pdata:
mutex_destroy(&tabla->codec_resource_lock);
@@ -8358,11 +8371,13 @@
wake_lock_destroy(&tabla->irq_resend_wlock);
- wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
- wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
- wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
- wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
- wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, tabla);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, tabla);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
+ tabla);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, tabla);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
+ tabla);
TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
tabla_codec_disable_clock_block(codec);
TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index a0a272f..d187ea5 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -2769,7 +2769,7 @@
/* reset retry counter as PA is turned off signifying
* start of new OCP detection session
*/
- if (TAIKO_IRQ_HPH_PA_OCPL_FAULT)
+ if (WCD9XXX_IRQ_HPH_PA_OCPL_FAULT)
taiko->hphlocp_cnt = 0;
else
taiko->hphrocp_cnt = 0;
@@ -2780,15 +2780,17 @@
static void hphlocp_off_report(struct work_struct *work)
{
struct taiko_priv *taiko = container_of(work, struct taiko_priv,
- hphlocp_work);
- hphocp_off_report(taiko, SND_JACK_OC_HPHL, TAIKO_IRQ_HPH_PA_OCPL_FAULT);
+ hphlocp_work);
+ hphocp_off_report(taiko, SND_JACK_OC_HPHL,
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
}
static void hphrocp_off_report(struct work_struct *work)
{
struct taiko_priv *taiko = container_of(work, struct taiko_priv,
- hphrocp_work);
- hphocp_off_report(taiko, SND_JACK_OC_HPHR, TAIKO_IRQ_HPH_PA_OCPR_FAULT);
+ hphrocp_work);
+ hphocp_off_report(taiko, SND_JACK_OC_HPHR,
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
}
static int taiko_hph_pa_event(struct snd_soc_dapm_widget *w,
@@ -4684,7 +4686,7 @@
short bias_value;
struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
- wcd9xxx_disable_irq(codec->control_data, TAIKO_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
if (noreldetection)
taiko_turn_onoff_rel_detection(codec, false);
@@ -4720,7 +4722,7 @@
if (noreldetection)
taiko_turn_onoff_rel_detection(codec, true);
- wcd9xxx_enable_irq(codec->control_data, TAIKO_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
return bias_value;
}
@@ -4907,9 +4909,9 @@
}
taiko_set_and_turnoff_hph_padac(codec);
hphocp_off_report(taiko, SND_JACK_OC_HPHR,
- TAIKO_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
hphocp_off_report(taiko, SND_JACK_OC_HPHL,
- TAIKO_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
taiko->current_plug = PLUG_TYPE_NONE;
taiko->mbhc_polling_active = false;
} else {
@@ -5053,7 +5055,7 @@
snd_soc_update_bits(codec, taiko->reg_addr.micb_4_mbhc, 0x3,
taiko->mbhc_cfg.micbias);
- wcd9xxx_enable_irq(codec->control_data, TAIKO_IRQ_MBHC_INSERTION);
+ wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
return 0;
}
@@ -5162,7 +5164,7 @@
taiko = snd_soc_codec_get_drvdata(codec);
calibration = taiko->mbhc_cfg.calibration;
- wcd9xxx_disable_irq(codec->control_data, TAIKO_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
taiko_turn_onoff_rel_detection(codec, false);
/* First compute the DCE / STA wait times
@@ -5245,7 +5247,7 @@
snd_soc_write(codec, TAIKO_A_MBHC_SCALING_MUX_1, 0x84);
usleep_range(100, 100);
- wcd9xxx_enable_irq(codec->control_data, TAIKO_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
taiko_turn_onoff_rel_detection(codec, true);
}
@@ -5795,7 +5797,7 @@
0x10);
} else {
wcd9xxx_disable_irq(codec->control_data,
- TAIKO_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
taiko->hphlocp_cnt = 0;
taiko->hph_status |= SND_JACK_OC_HPHL;
if (taiko->mbhc_cfg.headset_jack)
@@ -5828,7 +5830,7 @@
0x10);
} else {
wcd9xxx_disable_irq(codec->control_data,
- TAIKO_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
taiko->hphrocp_cnt = 0;
taiko->hph_status |= SND_JACK_OC_HPHR;
if (taiko->mbhc_cfg.headset_jack)
@@ -6354,7 +6356,7 @@
wcd9xxx_unlock_sleep(core);
} else {
wcd9xxx_enable_irq(codec->control_data,
- TAIKO_IRQ_MBHC_INSERTION);
+ WCD9XXX_IRQ_MBHC_INSERTION);
pr_err("%s: Error detecting plug insertion\n",
__func__);
}
@@ -6369,7 +6371,7 @@
pr_debug("%s: enter\n", __func__);
TAIKO_ACQUIRE_LOCK(priv->codec_resource_lock);
- wcd9xxx_disable_irq(codec->control_data, TAIKO_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
is_mb_trigger = !!(snd_soc_read(codec, priv->mbhc_bias_regs.mbhc_reg) &
0x10);
@@ -6593,7 +6595,8 @@
snd_soc_update_bits(codec, taiko->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
snd_soc_update_bits(codec, TAIKO_A_MBHC_HPH, 0x13, 0x00);
snd_soc_update_bits(codec, taiko->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
- wcd9xxx_disable_irq_sync(codec->control_data, TAIKO_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq_sync(codec->control_data,
+ WCD9XXX_IRQ_MBHC_INSERTION);
taiko_codec_detect_plug_type(codec);
wcd9xxx_unlock_sleep(taiko_core);
}
@@ -6728,9 +6731,9 @@
if (!IS_ERR_VALUE(ret)) {
snd_soc_update_bits(codec, TAIKO_A_RX_HPH_OCP_CTL, 0x10, 0x10);
wcd9xxx_enable_irq(codec->control_data,
- TAIKO_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
wcd9xxx_enable_irq(codec->control_data,
- TAIKO_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
if (taiko->mbhc_cfg.gpio) {
ret = request_threaded_irq(taiko->mbhc_cfg.gpio_irq,
@@ -7381,48 +7384,51 @@
int i;
struct snd_soc_codec *codec = taiko->codec;
- ret = wcd9xxx_request_irq(codec->control_data, TAIKO_IRQ_MBHC_INSERTION,
+ ret = wcd9xxx_request_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_INSERTION,
taiko_hs_insert_irq, "Headset insert detect",
taiko);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TAIKO_IRQ_MBHC_INSERTION);
+ WCD9XXX_IRQ_MBHC_INSERTION);
goto err_insert_irq;
}
- wcd9xxx_disable_irq(codec->control_data, TAIKO_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_INSERTION);
- ret = wcd9xxx_request_irq(codec->control_data, TAIKO_IRQ_MBHC_REMOVAL,
+ ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL,
taiko_hs_remove_irq, "Headset remove detect",
taiko);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TAIKO_IRQ_MBHC_REMOVAL);
+ WCD9XXX_IRQ_MBHC_REMOVAL);
goto err_remove_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data, TAIKO_IRQ_MBHC_POTENTIAL,
+ ret = wcd9xxx_request_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_POTENTIAL,
taiko_dce_handler, "DC Estimation detect",
taiko);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TAIKO_IRQ_MBHC_POTENTIAL);
+ WCD9XXX_IRQ_MBHC_POTENTIAL);
goto err_potential_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data, TAIKO_IRQ_MBHC_RELEASE,
+ ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE,
taiko_release_handler, "Button Release detect",
taiko);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TAIKO_IRQ_MBHC_RELEASE);
+ WCD9XXX_IRQ_MBHC_RELEASE);
goto err_release_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data, TAIKO_IRQ_SLIMBUS,
+ ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
taiko_slimbus_irq, "SLIMBUS Slave", taiko);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TAIKO_IRQ_SLIMBUS);
+ WCD9XXX_IRQ_SLIMBUS);
goto err_slimbus_irq;
}
@@ -7432,40 +7438,44 @@
0xFF);
ret = wcd9xxx_request_irq(codec->control_data,
- TAIKO_IRQ_HPH_PA_OCPL_FAULT,
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
taiko_hphl_ocp_irq,
"HPH_L OCP detect", taiko);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TAIKO_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
goto err_hphl_ocp_irq;
}
- wcd9xxx_disable_irq(codec->control_data, TAIKO_IRQ_HPH_PA_OCPL_FAULT);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
ret = wcd9xxx_request_irq(codec->control_data,
- TAIKO_IRQ_HPH_PA_OCPR_FAULT,
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
taiko_hphr_ocp_irq,
"HPH_R OCP detect", taiko);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TAIKO_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
goto err_hphr_ocp_irq;
}
- wcd9xxx_disable_irq(codec->control_data, TAIKO_IRQ_HPH_PA_OCPR_FAULT);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
+
+ return 0;
err_hphr_ocp_irq:
- wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_HPH_PA_OCPL_FAULT,
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
taiko);
err_hphl_ocp_irq:
- wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_SLIMBUS, taiko);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, taiko);
err_slimbus_irq:
- wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_RELEASE, taiko);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, taiko);
err_release_irq:
- wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_POTENTIAL, taiko);
+ wcd9xxx_free_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_POTENTIAL, taiko);
err_potential_irq:
- wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_REMOVAL, taiko);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, taiko);
err_remove_irq:
- wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_INSERTION, taiko);
+ wcd9xxx_free_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_INSERTION, taiko);
err_insert_irq:
return ret;
@@ -7600,11 +7610,13 @@
{
int i;
struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
- wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_SLIMBUS, taiko);
- wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_RELEASE, taiko);
- wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_POTENTIAL, taiko);
- wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_REMOVAL, taiko);
- wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_INSERTION, taiko);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, taiko);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, taiko);
+ wcd9xxx_free_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_POTENTIAL, taiko);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, taiko);
+ wcd9xxx_free_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_INSERTION, taiko);
TAIKO_ACQUIRE_LOCK(taiko->codec_resource_lock);
taiko_codec_disable_clock_block(codec);
TAIKO_RELEASE_LOCK(taiko->codec_resource_lock);