Merge "media: dvb: mpq: Add Support to use Deinterlacer"
diff --git a/Documentation/devicetree/bindings/hwmon/epm_adc.txt b/Documentation/devicetree/bindings/hwmon/epm_adc.txt
index 89edc16..a0ca490 100644
--- a/Documentation/devicetree/bindings/hwmon/epm_adc.txt
+++ b/Documentation/devicetree/bindings/hwmon/epm_adc.txt
@@ -9,7 +9,7 @@
EPM node
Required properties:
-- compatible : should be "qcom,epm-adc" for EPM using PSoC5.
+- compatible : should be "cy,epm-adc-cy8c5568lti-114" for EPM using PSoC5.
- reg : chip select for the device.
- interrupt-parent : should be phandle of the interrupt controller
servicing the interrupt for this device.
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index 51bf9e6..eda7cba 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -12,14 +12,14 @@
- compatible : should be "qcom,leds-qpnp"
Each LED module is represented as a node of "leds-qpnp". This
-node will furthur contain the type of LED supported and its
+node will further contain the type of LED supported and its
properties.
Required properties:
- qcom,id : must be one of values supported in enum qpnp_led
-- qcom,label : type of led that will be used, ie "wled"
+- label : type of led that will be used, ie "wled"
- qcom,max-current : maximum current that the LED can sustain
-= qcom,name : name the led will be called by in sysfs entry
+- linux,name : name of the led that is used in led framework
WLED is primarily used as display backlight. Display subsystem uses
LED triggers for WLED to control the brightness as needed.
@@ -41,17 +41,22 @@
qcom,leds@d800 {
compatible = "qcom,leds-qpnp";
- reg = <0xD800 0x100>;
- linux,default-trigger = "bkl-trigger"
- qcom,label = "wled";
- qcom,cs-out-en;
- qcom,op-fdbck;
- qcom,default-state "off";
- qcom,max-current = <25>;
- qcom,ctrl-delay-us = <0>;
- qcom,boost-curr-lim = <3>;
- qcom,cp-sel = <0>;
- qcom,switch-freq = <2>;
- qcom,ovp-val = <2>;
- qcom,num-strings = <1>;
- }
+ status = "okay";
+ qcom,wled_0 {
+ linux,default-trigger = "bkl-trigger"
+ label = "wled";
+ qcom,cs-out-en;
+ qcom,op-fdbck;
+ qcom,default-state "off";
+ qcom,max-current = <25>;
+ qcom,ctrl-delay-us = <0>;
+ qcom,boost-curr-lim = <3>;
+ qcom,cp-sel = <0>;
+ qcom,switch-freq = <2>;
+ qcom,ovp-val = <2>;
+ qcom,num-strings = <1>;
+ qcom,id = <0>;
+ linux,name = "led:wled_backlight";
+ };
+ };
+
diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
index af841dd..99274d5 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -28,6 +28,8 @@
- interrupt-names : Optional interrupt resource entries are:
"hs_phy_irq" : Interrupt from HSPHY for asynchronous events in LPM.
This is not used if wakeup events are received externally (e.g. PMIC)
+- qcom,dwc-usb3-msm-otg-capability: If present then depends on PMIC
+ for VBUS notifications, otherwise depends on PHY.
Example MSM USB3.0 controller device node :
usb@f9200000 {
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 1d95407..de30884 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -996,61 +996,61 @@
qcom,leds@d800 {
compatible = "qcom,leds-qpnp";
reg = <0xd800 0x100>;
- qcom,label = "wled";
+ label = "wled";
};
qcom,leds@d900 {
compatible = "qcom,leds-qpnp";
reg = <0xd900 0x100>;
- qcom,label = "wled";
+ label = "wled";
};
qcom,leds@da00 {
compatible = "qcom,leds-qpnp";
reg = <0xda00 0x100>;
- qcom,label = "wled";
+ label = "wled";
};
qcom,leds@db00 {
compatible = "qcom,leds-qpnp";
reg = <0xdb00 0x100>;
- qcom,label = "wled";
+ label = "wled";
};
qcom,leds@dc00 {
compatible = "qcom,leds-qpnp";
reg = <0xdc00 0x100>;
- qcom,label = "wled";
+ label = "wled";
};
qcom,leds@dd00 {
compatible = "qcom,leds-qpnp";
reg = <0xdd00 0x100>;
- qcom,label = "wled";
+ label = "wled";
};
qcom,leds@de00 {
compatible = "qcom,leds-qpnp";
reg = <0xde00 0x100>;
- qcom,label = "wled";
+ label = "wled";
};
qcom,leds@df00 {
compatible = "qcom,leds-qpnp";
reg = <0xdf00 0x100>;
- qcom,label = "wled";
+ label = "wled";
};
qcom,leds@e000 {
compatible = "qcom,leds-qpnp";
reg = <0xe000 0x100>;
- qcom,label = "wled";
+ label = "wled";
};
qcom,leds@e100 {
compatible = "qcom,leds-qpnp";
reg = <0xe100 0x100>;
- qcom,label = "wled";
+ label = "wled";
};
pwm@b100 {
diff --git a/arch/arm/boot/dts/msm8974-mtp.dts b/arch/arm/boot/dts/msm8974-mtp.dts
index b63595b..c5fabab 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-mtp.dts
@@ -177,6 +177,10 @@
qcom,hsusb-otg-otg-control = <2>;
};
+&usb3 {
+ qcom,dwc-usb3-msm-otg-capability;
+};
+
&pm8941_chg {
status = "ok";
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 3509e01..df3c520 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -261,6 +261,23 @@
<&msmgpio 54 0>, /* MISO */
<&msmgpio 53 0>; /* MOSI */
cs-gpios = <&msmgpio 55 0>;
+
+ epm-adc@0 {
+ compatible = "cy,epm-adc-cy8c5568lti-114";
+ reg = <0>;
+ interrupt-parent = <&msmgpio>;
+ spi-max-frequency = <960000>;
+ qcom,channels = <31>;
+ qcom,gain = <100 100 100 50 100 100 1 100 1 50
+ 1 100 1 100 50 50 50 50 50 50
+ 100 50 100 50 50 50 50 50 50 50
+ 50>;
+ qcom,rsense = <2 2 2 200 20 2 1 2 1 30
+ 1 10 1 30 50 30 500 30 100 30
+ 100 500 20 200 1000 20 1000 1000 70 200
+ 50>;
+ qcom,channel-type = <0x2a40>;
+ };
};
slim_msm: slim@fe12f000 {
@@ -511,19 +528,23 @@
qcom,pm8941@1 {
qcom,leds@d800 {
- qcom,name = "wled:backlight";
- linux,default-trigger = "bkl-trigger";
- qcom,cs-out-en;
- qcom,op-fdbck;
- qcom,default-state = "on";
- qcom,max-current = <25>;
- qcom,ctrl-delay-us = <0>;
- qcom,boost-curr-lim = <3>;
- qcom,cp-sel = <0>;
- qcom,switch-freq = <2>;
- qcom,ovp-val = <2>;
- qcom,num-strings = <1>;
status = "okay";
+ qcom,wled_0 {
+ label = "wled";
+ linux,name = "wled:backlight";
+ linux,default-trigger = "bkl-trigger";
+ qcom,cs-out-en;
+ qcom,op-fdbck;
+ qcom,default-state = "on";
+ qcom,max-current = <25>;
+ qcom,ctrl-delay-us = <0>;
+ qcom,boost-curr-lim = <3>;
+ qcom,cp-sel = <0>;
+ qcom,switch-freq = <2>;
+ qcom,ovp-val = <2>;
+ qcom,num-strings = <1>;
+ qcom,id = <0>;
+ };
};
qcom,leds@d900 {
@@ -630,12 +651,12 @@
l2_hfpll_b-supply = <&pm8941_l12_ao>;
};
- qcom,ssusb@f9200000 {
+ usb3: qcom,ssusb@f9200000 {
compatible = "qcom,dwc-usb3-msm";
reg = <0xf9200000 0xfc000>,
<0xfd4ab000 0x4>;
- interrupts = <0 131 0 0 179 0>;
- interrupt-names = "irq", "otg_irq";
+ interrupts = <0 131 0>, <0 179 0>, <0 133 0>;
+ interrupt-names = "irq", "otg_irq", "hs_phy_irq";
SSUSB_VDDCX-supply = <&pm8841_s2>;
SSUSB_1p8-supply = <&pm8941_l6>;
HSUSB_VDDCX-supply = <&pm8841_s2>;
@@ -1044,7 +1065,7 @@
qcom,dst-bam-physical-address = <0xf9304000>;
qcom,dst-bam-pipe-index = <2>;
qcom,data-fifo-offset = <0xf0000>;
- qcom,data-fifo-size = <0x4000>;
+ qcom,data-fifo-size = <0x1800>;
qcom,descriptor-fifo-offset = <0xf4000>;
qcom,descriptor-fifo-size = <0x1400>;
};
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 53e6260..ec00b68 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -367,6 +367,7 @@
CONFIG_S5K3L1YX=y
CONFIG_IMX091=y
CONFIG_MSM_WFD=y
+CONFIG_IMX135=y
CONFIG_RADIO_IRIS=y
CONFIG_RADIO_IRIS_TRANSPORT=m
# CONFIG_DVB_FE_CUSTOMISE is not set
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 5770859..33f7987 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -371,6 +371,7 @@
CONFIG_S5K3L1YX=y
CONFIG_IMX091=y
CONFIG_MSM_WFD=y
+CONFIG_IMX135=y
CONFIG_RADIO_IRIS=y
CONFIG_RADIO_IRIS_TRANSPORT=m
# CONFIG_DVB_FE_CUSTOMISE is not set
diff --git a/arch/arm/mach-msm/acpuclock-krait-debug.c b/arch/arm/mach-msm/acpuclock-krait-debug.c
index 0ab70b4..a29735e 100644
--- a/arch/arm/mach-msm/acpuclock-krait-debug.c
+++ b/arch/arm/mach-msm/acpuclock-krait-debug.c
@@ -35,7 +35,7 @@
bool set;
bool enable;
};
-static int l2_acg_en_val[MAX_SCALABLES];
+static int l2_acg_en_val;
static struct dentry *base_dir;
static struct dentry *sc_dir[MAX_SCALABLES];
@@ -51,8 +51,8 @@
val &= ~BIT(0);
else
val |= BIT(0);
- asm volatile ("mcr p15, 7, %[l2cpdr], c15, c0, 5\n\t"
- : : [l2cpdr]"r" (val));
+ asm volatile ("mcr p15, 7, %[cpmr0], c15, c0, 5\n\t"
+ : : [cpmr0]"r" (val));
} else {
action->enable = !(val & BIT(0));
}
@@ -65,7 +65,7 @@
if (sc_id == L2) {
regval = get_l2_indirect_reg(drv->scalable[sc_id].l2cpmr_iaddr);
- l2_acg_en_val[sc_id] = regval & (0x3 << 10);
+ l2_acg_en_val = regval & (0x3 << 10);
regval |= (0x3 << 10);
set_l2_indirect_reg(drv->scalable[sc_id].l2cpmr_iaddr, regval);
} else {
@@ -82,7 +82,7 @@
if (sc_id == L2) {
regval = get_l2_indirect_reg(drv->scalable[sc_id].l2cpmr_iaddr);
regval &= ~(0x3 << 10);
- regval |= l2_acg_en_val[sc_id];
+ regval |= l2_acg_en_val;
set_l2_indirect_reg(drv->scalable[sc_id].l2cpmr_iaddr, regval);
} else {
struct acg_action action = { .set = true, .enable = true };
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index a386e78..bf57eab 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-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 and
@@ -209,7 +209,8 @@
}
/* Set the CPU or L2 clock speed. */
-static void set_speed(struct scalable *sc, const struct core_speed *tgt_s)
+static void set_speed(struct scalable *sc, const struct core_speed *tgt_s,
+ bool skip_regulators)
{
const struct core_speed *strt_s = sc->cur_speed;
@@ -232,10 +233,10 @@
set_pri_clk_src(sc, tgt_s->pri_src_sel);
} else if (strt_s->src == HFPLL && tgt_s->src != HFPLL) {
set_pri_clk_src(sc, tgt_s->pri_src_sel);
- hfpll_disable(sc, false);
+ hfpll_disable(sc, skip_regulators);
} else if (strt_s->src != HFPLL && tgt_s->src == HFPLL) {
hfpll_set_rate(sc, tgt_s);
- hfpll_enable(sc, false);
+ hfpll_enable(sc, skip_regulators);
set_pri_clk_src(sc, tgt_s->pri_src_sel);
}
@@ -426,6 +427,47 @@
return tgt->vdd_core + (enable_boost ? drv.boost_uv : 0);
}
+static DEFINE_MUTEX(l2_regulator_lock);
+static int l2_vreg_count;
+
+static int enable_l2_regulators(void)
+{
+ int ret = 0;
+
+ mutex_lock(&l2_regulator_lock);
+ if (l2_vreg_count == 0) {
+ ret = enable_rpm_vreg(&drv.scalable[L2].vreg[VREG_HFPLL_A]);
+ if (ret)
+ goto out;
+ ret = enable_rpm_vreg(&drv.scalable[L2].vreg[VREG_HFPLL_B]);
+ if (ret) {
+ disable_rpm_vreg(&drv.scalable[L2].vreg[VREG_HFPLL_A]);
+ goto out;
+ }
+ }
+ l2_vreg_count++;
+out:
+ mutex_unlock(&l2_regulator_lock);
+
+ return ret;
+}
+
+static void disable_l2_regulators(void)
+{
+ mutex_lock(&l2_regulator_lock);
+
+ if (WARN(!l2_vreg_count, "L2 regulator votes are unbalanced!"))
+ goto out;
+
+ if (l2_vreg_count == 1) {
+ disable_rpm_vreg(&drv.scalable[L2].vreg[VREG_HFPLL_B]);
+ disable_rpm_vreg(&drv.scalable[L2].vreg[VREG_HFPLL_A]);
+ }
+ l2_vreg_count--;
+out:
+ mutex_unlock(&l2_regulator_lock);
+}
+
/* Set the CPU's clock rate and adjust the L2 rate, voltage and BW requests. */
static int acpuclk_krait_set_rate(int cpu, unsigned long rate,
enum setrate_reason reason)
@@ -433,8 +475,9 @@
const struct core_speed *strt_acpu_s, *tgt_acpu_s;
const struct acpu_level *tgt;
int tgt_l2_l;
+ enum src_id prev_l2_src = NUM_SRC_ID;
struct vdd_data vdd_data;
- unsigned long flags;
+ bool skip_regulators;
int rc = 0;
if (cpu > num_possible_cpus())
@@ -478,13 +521,31 @@
rc = increase_vdd(cpu, &vdd_data, reason);
if (rc)
goto out;
+
+ prev_l2_src =
+ drv.l2_freq_tbl[drv.scalable[cpu].l2_vote].speed.src;
+ /* Vote for the L2 regulators here if necessary. */
+ if (drv.l2_freq_tbl[tgt->l2_level].speed.src == HFPLL) {
+ rc = enable_l2_regulators();
+ if (rc)
+ goto out;
+ }
}
dev_dbg(drv.dev, "Switching from ACPU%d rate %lu KHz -> %lu KHz\n",
cpu, strt_acpu_s->khz, tgt_acpu_s->khz);
+ /*
+ * If we are setting the rate as part of power collapse or in the resume
+ * path after power collapse, skip the vote for the HFPLL regulators,
+ * which are active-set-only votes that will be removed when apps enters
+ * its sleep set. This is needed to avoid voting for regulators with
+ * sleeping APIs from an atomic context.
+ */
+ skip_regulators = (reason == SETRATE_PC);
+
/* Set the new CPU speed. */
- set_speed(&drv.scalable[cpu], tgt_acpu_s);
+ set_speed(&drv.scalable[cpu], tgt_acpu_s, skip_regulators);
/*
* Update the L2 vote and apply the rate change. A spinlock is
@@ -493,15 +554,23 @@
* called from an atomic context and the driver_lock mutex is not
* acquired.
*/
- spin_lock_irqsave(&l2_lock, flags);
+ spin_lock(&l2_lock);
tgt_l2_l = compute_l2_level(&drv.scalable[cpu], tgt->l2_level);
- set_speed(&drv.scalable[L2], &drv.l2_freq_tbl[tgt_l2_l].speed);
- spin_unlock_irqrestore(&l2_lock, flags);
+ set_speed(&drv.scalable[L2],
+ &drv.l2_freq_tbl[tgt_l2_l].speed, true);
+ spin_unlock(&l2_lock);
/* Nothing else to do for power collapse or SWFI. */
if (reason == SETRATE_PC || reason == SETRATE_SWFI)
goto out;
+ /*
+ * Remove the vote for the L2 HFPLL regulators only if the L2
+ * was already on an HFPLL source.
+ */
+ if (prev_l2_src == HFPLL)
+ disable_l2_regulators();
+
/* Update bus bandwith request. */
set_bus_bw(drv.l2_freq_tbl[tgt_l2_l].bw_level);
@@ -663,6 +732,14 @@
goto err_core_conf;
}
+ /*
+ * Increment the L2 HFPLL regulator refcount if _this_ CPU's frequency
+ * requires a corresponding target L2 frequency that needs the L2 to
+ * run off of an HFPLL.
+ */
+ if (drv.l2_freq_tbl[acpu_level->l2_level].speed.src == HFPLL)
+ l2_vreg_count++;
+
return 0;
err_core_conf:
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index c0e325a..c973bd5 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -143,6 +143,7 @@
static struct pm8xxx_gpio_init pm8921_mpq8064_hrd_gpios[] __initdata = {
PM8921_GPIO_OUTPUT(37, 0, LOW), /* MUX1_SEL */
+ PM8921_GPIO_INPUT(40, PM_GPIO_PULL_UP_30), /* irq for sx150 exp2 */
};
static struct pm8xxx_gpio_init touchscreen_gpios[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index 379d7ae..28f7f63 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -383,6 +383,14 @@
apq8064_sdc3_pdata->pin_data->pad_data->\
drv->on[i].val = GPIO_CFG_10MA;
}
+ if (machine_is_mpq8064_hrd() || machine_is_mpq8064_dtv()) {
+ apq8064_sdc3_pdata->pin_data->pad_data->\
+ drv->on[0].val = GPIO_CFG_16MA;
+ apq8064_sdc3_pdata->pin_data->pad_data->\
+ drv->on[1].val = GPIO_CFG_10MA;
+ apq8064_sdc3_pdata->pin_data->pad_data->\
+ drv->on[2].val = GPIO_CFG_10MA;
+ }
apq8064_add_sdcc(3, apq8064_sdc3_pdata);
}
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 9e5e4f5..6a3e78e 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2401,6 +2401,7 @@
static struct platform_device *common_mpq_devices[] __initdata = {
&mpq_cpudai_sec_i2s_rx,
&mpq_cpudai_mi2s_tx,
+ &mpq_cpudai_pseudo,
};
static struct platform_device *common_i2s_devices[] __initdata = {
@@ -2945,6 +2946,83 @@
},
};
+#define MPQ_HRD_HOME_GPIO SX150X_EXP2_GPIO_BASE
+#define MPQ_HRD_VOL_UP_GPIO (SX150X_EXP2_GPIO_BASE + 1)
+#define MPQ_HRD_VOL_DOWN_GPIO (SX150X_EXP2_GPIO_BASE + 2)
+#define MPQ_HRD_RIGHT_GPIO (SX150X_EXP2_GPIO_BASE + 3)
+#define MPQ_HRD_LEFT_GPIO (SX150X_EXP2_GPIO_BASE + 4)
+#define MPQ_HRD_ENTER_GPIO (SX150X_EXP2_GPIO_BASE + 5)
+
+static struct gpio_keys_button mpq_hrd_keys[] = {
+ {
+ .code = KEY_HOME,
+ .gpio = MPQ_HRD_HOME_GPIO,
+ .desc = "home_key",
+ .active_low = 1,
+ .type = EV_KEY,
+ .wakeup = 1,
+ .debounce_interval = 15,
+ },
+ {
+ .code = KEY_VOLUMEUP,
+ .gpio = MPQ_HRD_VOL_UP_GPIO,
+ .desc = "volume_up_key",
+ .active_low = 1,
+ .type = EV_KEY,
+ .wakeup = 1,
+ .debounce_interval = 15,
+ },
+ {
+ .code = KEY_VOLUMEDOWN,
+ .gpio = MPQ_HRD_VOL_DOWN_GPIO,
+ .desc = "volume_down_key",
+ .active_low = 1,
+ .type = EV_KEY,
+ .wakeup = 1,
+ .debounce_interval = 15,
+ },
+ {
+ .code = KEY_RIGHT,
+ .gpio = MPQ_HRD_RIGHT_GPIO,
+ .desc = "right_key",
+ .active_low = 1,
+ .type = EV_KEY,
+ .wakeup = 1,
+ .debounce_interval = 15,
+ },
+ {
+ .code = KEY_LEFT,
+ .gpio = MPQ_HRD_LEFT_GPIO,
+ .desc = "left_key",
+ .active_low = 1,
+ .type = EV_KEY,
+ .wakeup = 1,
+ .debounce_interval = 15,
+ },
+ {
+ .code = KEY_ENTER,
+ .gpio = MPQ_HRD_ENTER_GPIO,
+ .desc = "enter_key",
+ .active_low = 1,
+ .type = EV_KEY,
+ .wakeup = 1,
+ .debounce_interval = 15,
+ },
+};
+
+static struct gpio_keys_platform_data mpq_hrd_keys_pdata = {
+ .buttons = mpq_hrd_keys,
+ .nbuttons = ARRAY_SIZE(mpq_hrd_keys),
+};
+
+static struct platform_device mpq_hrd_keys_pdev = {
+ .name = "gpio-keys",
+ .id = -1,
+ .dev = {
+ .platform_data = &mpq_hrd_keys_pdata,
+ },
+};
+
static struct gpio_keys_button mpq_keys[] = {
{
.code = KEY_VOLUMEDOWN,
@@ -3300,6 +3378,15 @@
msm_clock_init(&apq8064_clock_init_data);
apq8064_init_gpiomux();
apq8064_i2c_init();
+
+ /* configure sx150x parameters for HRD */
+ if (machine_is_mpq8064_hrd()) {
+ mpq8064_sx150x_pdata[SX150X_EXP2].irq_summary =
+ PM8921_GPIO_IRQ(PM8921_IRQ_BASE, 40);
+ mpq8064_sx150x_pdata[SX150X_EXP2].io_pullup_ena = 0xff;
+ mpq8064_sx150x_pdata[SX150X_EXP2].io_pulldn_ena = 0x00;
+ }
+
register_i2c_devices();
apq8064_device_qup_spi_gsbi5.dev.platform_data =
@@ -3446,7 +3533,8 @@
if (machine_is_mpq8064_cdp()) {
platform_device_register(&mpq_gpio_keys_pdev);
platform_device_register(&mpq_keypad_device);
- }
+ } else if (machine_is_mpq8064_hrd())
+ platform_device_register(&mpq_hrd_keys_pdev);
}
MACHINE_START(APQ8064_CDP, "QCT APQ8064 CDP")
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index e919d78..ce2531b 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -3287,7 +3287,13 @@
msm_spm_l2_init(msm_spm_l2_data);
msm8960_init_buses();
- platform_add_devices(msm8960_footswitch, msm8960_num_footswitch);
+ if (cpu_is_msm8960ab()) {
+ platform_add_devices(msm8960ab_footswitch,
+ msm8960ab_num_footswitch);
+ } else {
+ platform_add_devices(msm8960_footswitch,
+ msm8960_num_footswitch);
+ }
if (machine_is_msm8960_liquid())
platform_device_register(&msm8960_device_ext_3p3v_vreg);
if (machine_is_msm8960_cdp())
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index d727c54..127c9ab 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -542,6 +542,10 @@
.id = 0x4009,
};
+struct platform_device mpq_cpudai_pseudo = {
+ .name = "msm-dai-q6",
+ .id = 0x8001,
+};
#define MSM_TSIF0_PHYS (0x18200000)
#define MSM_TSIF1_PHYS (0x18201000)
#define MSM_TSIF_SIZE (0x200)
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index 30a99cd..322347b 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -1083,6 +1083,7 @@
#endif
.disable_dmx = 1,
.disable_fullhd = 0,
+ .cont_mode_dpb_count = 18,
.fw_addr = 0x9fe00000,
};
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 0f71bc4..f8132b4 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -2553,6 +2553,17 @@
};
unsigned msm8960_num_footswitch __initdata = ARRAY_SIZE(msm8960_footswitch);
+struct platform_device *msm8960ab_footswitch[] __initdata = {
+ FS_8X60(FS_MDP, "vdd", "mdp.0", &mdp_fs_data),
+ FS_8X60(FS_ROT, "vdd", "msm_rotator.0", &rot_fs_data),
+ FS_8X60(FS_IJPEG, "vdd", "msm_gemini.0", &ijpeg_fs_data),
+ FS_8X60(FS_VFE, "vdd", "msm_vfe.0", &vfe_fs_data),
+ FS_8X60(FS_VPE, "vdd", "msm_vpe.0", &vpe_fs_data),
+ FS_8X60(FS_GFX3D, "vdd", "kgsl-3d0.0", &gfx3d_fs_data),
+ FS_8X60(FS_VED, "vdd", "msm_vidc.0", &ved_fs_data),
+};
+unsigned msm8960ab_num_footswitch __initdata = ARRAY_SIZE(msm8960ab_footswitch);
+
#ifdef CONFIG_MSM_ROTATOR
static struct msm_bus_vectors rotator_init_vectors[] = {
{
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 8f02050..861f1d6 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -216,6 +216,7 @@
extern struct platform_device msm_cpudai0;
extern struct platform_device msm_cpudai1;
extern struct platform_device mpq_cpudai_sec_i2s_rx;
+extern struct platform_device mpq_cpudai_pseudo;
extern struct platform_device msm8960_cpudai_slimbus_2_rx;
extern struct platform_device msm8960_cpudai_slimbus_2_tx;
extern struct platform_device msm_cpudai_hdmi_rx;
@@ -300,6 +301,8 @@
extern unsigned msm8660_num_footswitch;
extern struct platform_device *msm8960_footswitch[];
extern unsigned msm8960_num_footswitch;
+extern struct platform_device *msm8960ab_footswitch[];
+extern unsigned msm8960ab_num_footswitch;
extern struct platform_device *apq8064_footswitch[];
extern unsigned apq8064_num_footswitch;
extern struct platform_device *msm8930_footswitch[];
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 20e56c2..3a632e5 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -96,6 +96,13 @@
static struct list_head local_ports[LP_HASH_SIZE];
static DEFINE_MUTEX(local_ports_lock);
+/*
+ * Server info is organized as a hash table. The server's service ID is
+ * used to index into the hash table. The instance ID of most of the servers
+ * are 1 or 2. The service IDs are well distributed compared to the instance
+ * IDs and hence choosing service ID to index into this hash table optimizes
+ * the hash table operations like add, lookup, destroy.
+ */
#define SRV_HASH_SIZE 32
static struct list_head server_list[SRV_HASH_SIZE];
static DEFINE_MUTEX(server_list_lock);
@@ -581,6 +588,20 @@
return;
}
+/**
+ * msm_ipc_router_lookup_server() - Lookup server information
+ * @service: Service ID of the server info to be looked up.
+ * @instance: Instance ID of the server info to be looked up.
+ * @node_id: Node/Processor ID in which the server is hosted.
+ * @port_id: Port ID within the node in which the server is hosted.
+ *
+ * @return: If found Pointer to server structure, else NULL.
+ *
+ * Note1: Lock the server_list_lock before accessing this function.
+ * Note2: If the <node_id:port_id> are <0:0>, then the lookup is restricted
+ * to <service:instance>. Used only when a client wants to send a
+ * message to any QMI server.
+ */
static struct msm_ipc_server *msm_ipc_router_lookup_server(
uint32_t service,
uint32_t instance,
@@ -589,30 +610,39 @@
{
struct msm_ipc_server *server;
struct msm_ipc_server_port *server_port;
- int key = (instance & (SRV_HASH_SIZE - 1));
+ int key = (service & (SRV_HASH_SIZE - 1));
- mutex_lock(&server_list_lock);
list_for_each_entry(server, &server_list[key], list) {
if ((server->name.service != service) ||
(server->name.instance != instance))
continue;
- if ((node_id == 0) && (port_id == 0)) {
- mutex_unlock(&server_list_lock);
+ if ((node_id == 0) && (port_id == 0))
return server;
- }
list_for_each_entry(server_port, &server->server_port_list,
list) {
if ((server_port->server_addr.node_id == node_id) &&
- (server_port->server_addr.port_id == port_id)) {
- mutex_unlock(&server_list_lock);
+ (server_port->server_addr.port_id == port_id))
return server;
- }
}
}
- mutex_unlock(&server_list_lock);
return NULL;
}
+/**
+ * msm_ipc_router_create_server() - Add server info to hash table
+ * @service: Service ID of the server info to be created.
+ * @instance: Instance ID of the server info to be created.
+ * @node_id: Node/Processor ID in which the server is hosted.
+ * @port_id: Port ID within the node in which the server is hosted.
+ * @xprt_info: XPRT through which the node hosting the server is reached.
+ *
+ * @return: Pointer to server structure on success, else NULL.
+ *
+ * This function adds the server info to the hash table. If the same
+ * server(i.e. <service_id:instance_id>) is hosted in different nodes,
+ * they are maintained as list of "server_port" under "server" structure.
+ * Note: Lock the server_list_lock before accessing this function.
+ */
static struct msm_ipc_server *msm_ipc_router_create_server(
uint32_t service,
uint32_t instance,
@@ -622,9 +652,8 @@
{
struct msm_ipc_server *server = NULL;
struct msm_ipc_server_port *server_port;
- int key = (instance & (SRV_HASH_SIZE - 1));
+ int key = (service & (SRV_HASH_SIZE - 1));
- mutex_lock(&server_list_lock);
list_for_each_entry(server, &server_list[key], list) {
if ((server->name.service == service) &&
(server->name.instance == instance))
@@ -633,7 +662,6 @@
server = kmalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
if (!server) {
- mutex_unlock(&server_list_lock);
pr_err("%s: Server allocation failed\n", __func__);
return NULL;
}
@@ -649,7 +677,6 @@
list_del(&server->list);
kfree(server);
}
- mutex_unlock(&server_list_lock);
pr_err("%s: Server Port allocation failed\n", __func__);
return NULL;
}
@@ -657,11 +684,22 @@
server_port->server_addr.port_id = port_id;
server_port->xprt_info = xprt_info;
list_add_tail(&server_port->list, &server->server_port_list);
- mutex_unlock(&server_list_lock);
return server;
}
+/**
+ * msm_ipc_router_destroy_server() - Remove server info from hash table
+ * @server: Server info to be removed.
+ * @node_id: Node/Processor ID in which the server is hosted.
+ * @port_id: Port ID within the node in which the server is hosted.
+ *
+ * This function removes the server_port identified using <node_id:port_id>
+ * from the server structure. If the server_port list under server structure
+ * is empty after removal, then remove the server structure from the server
+ * hash table.
+ * Note: Lock the server_list_lock before accessing this function.
+ */
static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
uint32_t node_id, uint32_t port_id)
{
@@ -670,7 +708,6 @@
if (!server)
return;
- mutex_lock(&server_list_lock);
list_for_each_entry(server_port, &server->server_port_list, list) {
if ((server_port->server_addr.node_id == node_id) &&
(server_port->server_addr.port_id == port_id))
@@ -684,7 +721,6 @@
list_del(&server->list);
kfree(server);
}
- mutex_unlock(&server_list_lock);
return;
}
@@ -1319,6 +1355,7 @@
}
mutex_unlock(&routing_table_lock);
+ mutex_lock(&server_list_lock);
server = msm_ipc_router_lookup_server(msg->srv.service,
msg->srv.instance,
msg->srv.node_id,
@@ -1328,6 +1365,7 @@
msg->srv.service, msg->srv.instance,
msg->srv.node_id, msg->srv.port_id, xprt_info);
if (!server) {
+ mutex_unlock(&server_list_lock);
pr_err("%s: Server Create failed\n", __func__);
return -ENOMEM;
}
@@ -1342,6 +1380,7 @@
}
wake_up(&newserver_wait);
}
+ mutex_unlock(&server_list_lock);
relay_msg(xprt_info, pkt);
post_control_ports(pkt);
@@ -1349,6 +1388,7 @@
case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
RR("o REMOVE_SERVER service=%08x:%d\n",
msg->srv.service, msg->srv.instance);
+ mutex_lock(&server_list_lock);
server = msm_ipc_router_lookup_server(msg->srv.service,
msg->srv.instance,
msg->srv.node_id,
@@ -1360,6 +1400,7 @@
relay_msg(xprt_info, pkt);
post_control_ports(pkt);
}
+ mutex_unlock(&server_list_lock);
break;
case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
RR("o REMOVE_CLIENT id=%d:%08x\n",
@@ -1544,11 +1585,13 @@
if (name->addrtype != MSM_IPC_ADDR_NAME)
return -EINVAL;
+ mutex_lock(&server_list_lock);
server = msm_ipc_router_lookup_server(name->addr.port_name.service,
name->addr.port_name.instance,
IPC_ROUTER_NID_LOCAL,
port_ptr->this_port.port_id);
if (server) {
+ mutex_unlock(&server_list_lock);
pr_err("%s: Server already present\n", __func__);
return -EINVAL;
}
@@ -1559,6 +1602,7 @@
port_ptr->this_port.port_id,
NULL);
if (!server) {
+ mutex_unlock(&server_list_lock);
pr_err("%s: Server Creation failed\n", __func__);
return -EINVAL;
}
@@ -1568,6 +1612,7 @@
ctl.srv.instance = server->name.instance;
ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
ctl.srv.port_id = port_ptr->this_port.port_id;
+ mutex_unlock(&server_list_lock);
broadcast_ctl_msg(&ctl);
spin_lock_irqsave(&port_ptr->port_lock, flags);
port_ptr->type = SERVER_PORT;
@@ -1598,11 +1643,13 @@
return -EINVAL;
}
+ mutex_lock(&server_list_lock);
server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
port_ptr->port_name.instance,
port_ptr->this_port.node_id,
port_ptr->this_port.port_id);
if (!server) {
+ mutex_unlock(&server_list_lock);
pr_err("%s: Server lookup failed\n", __func__);
return -ENODEV;
}
@@ -1612,9 +1659,10 @@
ctl.srv.instance = server->name.instance;
ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
ctl.srv.port_id = port_ptr->this_port.port_id;
- broadcast_ctl_msg(&ctl);
msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
port_ptr->this_port.port_id);
+ mutex_unlock(&server_list_lock);
+ broadcast_ctl_msg(&ctl);
spin_lock_irqsave(&port_ptr->port_lock, flags);
port_ptr->type = CLIENT_PORT;
spin_unlock_irqrestore(&port_ptr->port_lock, flags);
@@ -1813,15 +1861,16 @@
dst_node_id = dest->addr.port_addr.node_id;
dst_port_id = dest->addr.port_addr.port_id;
} else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
+ mutex_lock(&server_list_lock);
server = msm_ipc_router_lookup_server(
dest->addr.port_name.service,
dest->addr.port_name.instance,
0, 0);
if (!server) {
+ mutex_unlock(&server_list_lock);
pr_err("%s: Destination not reachable\n", __func__);
return -ENODEV;
}
- mutex_lock(&server_list_lock);
server_port = list_first_entry(&server->server_port_list,
struct msm_ipc_server_port,
list);
@@ -2005,6 +2054,7 @@
mutex_unlock(&port_ptr->port_rx_q_lock);
if (port_ptr->type == SERVER_PORT) {
+ mutex_lock(&server_list_lock);
server = msm_ipc_router_lookup_server(
port_ptr->port_name.service,
port_ptr->port_name.instance,
@@ -2014,6 +2064,7 @@
msm_ipc_router_destroy_server(server,
port_ptr->this_port.node_id,
port_ptr->this_port.port_id);
+ mutex_unlock(&server_list_lock);
}
wake_lock_destroy(&port_ptr->port_rx_wake_lock);
@@ -2078,27 +2129,24 @@
mutex_lock(&server_list_lock);
if (!lookup_mask)
lookup_mask = 0xFFFFFFFF;
- for (key = 0; key < SRV_HASH_SIZE; key++) {
- list_for_each_entry(server, &server_list[key], list) {
- if ((server->name.service != srv_name->service) ||
- ((server->name.instance & lookup_mask) !=
- srv_name->instance))
- continue;
+ key = (srv_name->service & (SRV_HASH_SIZE - 1));
+ list_for_each_entry(server, &server_list[key], list) {
+ if ((server->name.service != srv_name->service) ||
+ ((server->name.instance & lookup_mask) !=
+ srv_name->instance))
+ continue;
- list_for_each_entry(server_port,
- &server->server_port_list, list) {
- if (i < num_entries_in_array) {
- srv_info[i].node_id =
+ list_for_each_entry(server_port,
+ &server->server_port_list, list) {
+ if (i < num_entries_in_array) {
+ srv_info[i].node_id =
server_port->server_addr.node_id;
- srv_info[i].port_id =
+ srv_info[i].port_id =
server_port->server_addr.port_id;
- srv_info[i].service =
- server->name.service;
- srv_info[i].instance =
- server->name.instance;
- }
- i++;
+ srv_info[i].service = server->name.service;
+ srv_info[i].instance = server->name.instance;
}
+ i++;
}
}
mutex_unlock(&server_list_lock);
diff --git a/arch/arm/mach-msm/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
index 3731722..0f17a0b 100644
--- a/arch/arm/mach-msm/qdsp6v2/Makefile
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -8,6 +8,7 @@
obj-y += q6voice.o
obj-y += snddev_hdmi.o
obj-y += audio_mvs.o
+obj-$(CONFIG_ARCH_MSM8X60) += pcm_in_proxy.o
obj-$(CONFIG_FB_MSM_HDMI_MSM_PANEL) += lpa_if_hdmi.o
endif
obj-$(CONFIG_MSM_QDSP6_APR) += apr.o apr_v1.o apr_tal.o q6core.o dsp_debug.o
diff --git a/arch/arm/mach-msm/qdsp6v2/adsprpc.c b/arch/arm/mach-msm/qdsp6v2/adsprpc.c
index 49008de..822da91 100644
--- a/arch/arm/mach-msm/qdsp6v2/adsprpc.c
+++ b/arch/arm/mach-msm/qdsp6v2/adsprpc.c
@@ -11,6 +11,7 @@
* GNU General Public License for more details.
*
*/
+#include <linux/scatterlist.h>
#include "adsprpc.h"
struct smq_invoke_ctx {
@@ -70,14 +71,25 @@
static int alloc_mem(struct fastrpc_buf *buf)
{
struct ion_client *clnt = gfa.iclient;
+ struct sg_table *sg;
int err = 0;
buf->handle = ion_alloc(clnt, buf->size, SZ_4K,
ION_HEAP(ION_AUDIO_HEAP_ID), 0);
- VERIFY(0 == IS_ERR_OR_NULL(buf->handle));
+ VERIFY(err, 0 == IS_ERR_OR_NULL(buf->handle));
+ if (err)
+ goto bail;
buf->virt = 0;
- VERIFY(0 != (buf->virt = ion_map_kernel(clnt, buf->handle)));
- VERIFY(0 == ion_phys(clnt, buf->handle, &buf->phys, &buf->size));
+ VERIFY(err, 0 != (buf->virt = ion_map_kernel(clnt, buf->handle)));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 != (sg = ion_sg_table(clnt, buf->handle)));
+ if (err)
+ goto bail;
+ VERIFY(err, 1 == sg->nents);
+ if (err)
+ goto bail;
+ buf->phys = sg_dma_address(sg->sgl);
bail:
if (err && !IS_ERR_OR_NULL(buf->handle))
free_mem(buf);
@@ -87,7 +99,9 @@
static int context_list_ctor(struct smq_context_list *me, int size)
{
int err = 0;
- VERIFY(0 != (me->ls = kzalloc(size, GFP_KERNEL)));
+ VERIFY(err, 0 != (me->ls = kzalloc(size, GFP_KERNEL)));
+ if (err)
+ goto bail;
me->size = size / sizeof(*me->ls);
me->last = 0;
bail:
@@ -103,18 +117,18 @@
static void context_list_alloc_ctx(struct smq_context_list *me,
struct smq_invoke_ctx **po)
{
- int ii = me->last;
+ int i = me->last;
struct smq_invoke_ctx *ctx;
for (;;) {
- ii = ii % me->size;
- ctx = &me->ls[ii];
+ i = i % me->size;
+ ctx = &me->ls[i];
if (atomic_read(&ctx->free) == 0)
- if (0 == atomic_cmpxchg(&ctx->free, 0, 1))
+ if (atomic_cmpxchg(&ctx->free, 0, 1) == 0)
break;
- ii++;
+ i++;
}
- me->last = ii;
+ me->last = i;
ctx->retval = -1;
init_completion(&ctx->work);
*po = ctx;
@@ -134,13 +148,13 @@
static void context_notify_all_users(struct smq_context_list *me)
{
- int ii;
+ int i;
if (!me->ls)
return;
- for (ii = 0; ii < me->size; ++ii) {
- if (atomic_read(&me->ls[ii].free) != 0)
- complete(&me->ls[ii].work);
+ for (i = 0; i < me->size; ++i) {
+ if (atomic_read(&me->ls[i].free) != 0)
+ complete(&me->ls[i].work);
}
}
@@ -149,11 +163,10 @@
{
struct smq_phy_page *pgstart, *pages;
struct smq_invoke_buf *list;
- int ii, rlen, err = 0;
+ int i, rlen, err = 0;
int inbufs = REMOTE_SCALARS_INBUFS(sc);
int outbufs = REMOTE_SCALARS_OUTBUFS(sc);
- VERIFY(0 != try_module_get(THIS_MODULE));
LOCK_MMAP(kernel);
*obuf = *ibuf;
retry:
@@ -165,38 +178,46 @@
rlen = ((uint32_t)pages - (uint32_t)obuf->virt) - obuf->size;
obuf->size += buf_page_size(rlen);
obuf->handle = 0;
- VERIFY(0 == alloc_mem(obuf));
+ VERIFY(err, 0 == alloc_mem(obuf));
+ if (err)
+ goto bail;
goto retry;
}
pgstart->addr = obuf->phys;
pgstart->size = obuf->size;
- for (ii = 0; ii < inbufs + outbufs; ++ii) {
+ for (i = 0; i < inbufs + outbufs; ++i) {
void *buf;
int len, num;
- len = pra[ii].buf.len;
+ list[i].num = 0;
+ list[i].pgidx = 0;
+ len = pra[i].buf.len;
if (!len)
continue;
- buf = pra[ii].buf.pv;
+ buf = pra[i].buf.pv;
num = buf_num_pages(buf, len);
if (!kernel)
- list[ii].num = buf_get_pages(buf, len, num,
- ii >= inbufs, pages, rlen / sizeof(*pages));
+ list[i].num = buf_get_pages(buf, len, num,
+ i >= inbufs, pages, rlen / sizeof(*pages));
else
- list[ii].num = 0;
- VERIFY(list[ii].num >= 0);
- if (list[ii].num) {
- list[ii].pgidx = pages - pgstart;
- pages = pages + list[ii].num;
+ list[i].num = 0;
+ VERIFY(err, list[i].num >= 0);
+ if (err)
+ goto bail;
+ if (list[i].num) {
+ list[i].pgidx = pages - pgstart;
+ pages = pages + list[i].num;
} else if (rlen > sizeof(*pages)) {
- list[ii].pgidx = pages - pgstart;
+ list[i].pgidx = pages - pgstart;
pages = pages + 1;
} else {
if (obuf->handle != ibuf->handle)
free_mem(obuf);
obuf->size += buf_page_size(sizeof(*pages));
obuf->handle = 0;
- VERIFY(0 == alloc_mem(obuf));
+ VERIFY(err, 0 == alloc_mem(obuf));
+ if (err)
+ goto bail;
goto retry;
}
rlen = obuf->size - ((uint32_t) pages - (uint32_t) obuf->virt);
@@ -206,7 +227,6 @@
if (err && (obuf->handle != ibuf->handle))
free_mem(obuf);
UNLOCK_MMAP(kernel);
- module_put(THIS_MODULE);
return err;
}
@@ -219,74 +239,86 @@
struct fastrpc_buf *pbuf = ibuf, *obufs = 0;
struct smq_phy_page *pages;
void *args;
- int ii, rlen, size, used, inh, bufs = 0, err = 0;
+ int i, rlen, size, used, inh, bufs = 0, err = 0;
int inbufs = REMOTE_SCALARS_INBUFS(sc);
int outbufs = REMOTE_SCALARS_OUTBUFS(sc);
list = smq_invoke_buf_start(rpra, sc);
pages = smq_phy_page_start(sc, list);
- used = ALIGN_8(pbuf->used);
+ used = ALIGN(pbuf->used, BALIGN);
args = (void *)((char *)pbuf->virt + used);
rlen = pbuf->size - used;
- for (ii = 0; ii < inbufs + outbufs; ++ii) {
+ for (i = 0; i < inbufs + outbufs; ++i) {
int num;
- rpra[ii].buf.len = pra[ii].buf.len;
- if (list[ii].num) {
- rpra[ii].buf.pv = pra[ii].buf.pv;
+ rpra[i].buf.len = pra[i].buf.len;
+ if (!rpra[i].buf.len)
+ continue;
+ if (list[i].num) {
+ rpra[i].buf.pv = pra[i].buf.pv;
continue;
}
- if (rlen < pra[ii].buf.len) {
+ if (rlen < pra[i].buf.len) {
struct fastrpc_buf *b;
pbuf->used = pbuf->size - rlen;
- VERIFY(0 != (b = krealloc(obufs,
+ VERIFY(err, 0 != (b = krealloc(obufs,
(bufs + 1) * sizeof(*obufs), GFP_KERNEL)));
+ if (err)
+ goto bail;
obufs = b;
pbuf = obufs + bufs;
- pbuf->size = buf_num_pages(0, pra[ii].buf.len) *
+ pbuf->size = buf_num_pages(0, pra[i].buf.len) *
PAGE_SIZE;
- VERIFY(0 == alloc_mem(pbuf));
+ VERIFY(err, 0 == alloc_mem(pbuf));
+ if (err)
+ goto bail;
bufs++;
args = pbuf->virt;
rlen = pbuf->size;
}
- num = buf_num_pages(args, pra[ii].buf.len);
+ num = buf_num_pages(args, pra[i].buf.len);
if (pbuf == ibuf) {
- list[ii].num = num;
- list[ii].pgidx = 0;
+ list[i].num = num;
+ list[i].pgidx = 0;
} else {
- list[ii].num = 1;
- pages[list[ii].pgidx].addr =
+ list[i].num = 1;
+ pages[list[i].pgidx].addr =
buf_page_start((void *)(pbuf->phys +
(pbuf->size - rlen)));
- pages[list[ii].pgidx].size =
- buf_page_size(pra[ii].buf.len);
+ pages[list[i].pgidx].size =
+ buf_page_size(pra[i].buf.len);
}
- if (ii < inbufs) {
- if (!kernel)
- VERIFY(0 == copy_from_user(args, pra[ii].buf.pv,
- pra[ii].buf.len));
- else
- memmove(args, pra[ii].buf.pv, pra[ii].buf.len);
+ if (i < inbufs) {
+ if (!kernel) {
+ VERIFY(err, 0 == copy_from_user(args,
+ pra[i].buf.pv, pra[i].buf.len));
+ if (err)
+ goto bail;
+ } else {
+ memmove(args, pra[i].buf.pv, pra[i].buf.len);
+ }
}
- rpra[ii].buf.pv = args;
- args = (void *)((char *)args + ALIGN_8(pra[ii].buf.len));
- rlen -= ALIGN_8(pra[ii].buf.len);
+ rpra[i].buf.pv = args;
+ args = (void *)((char *)args + ALIGN(pra[i].buf.len, BALIGN));
+ rlen -= ALIGN(pra[i].buf.len, BALIGN);
}
- for (ii = 0; ii < inbufs; ++ii) {
- if (rpra[ii].buf.len)
- dmac_flush_range(rpra[ii].buf.pv,
- (char *)rpra[ii].buf.pv + rpra[ii].buf.len);
+ for (i = 0; i < inbufs; ++i) {
+ if (rpra[i].buf.len)
+ dmac_flush_range(rpra[i].buf.pv,
+ (char *)rpra[i].buf.pv + rpra[i].buf.len);
}
pbuf->used = pbuf->size - rlen;
size = sizeof(*rpra) * REMOTE_SCALARS_INHANDLES(sc);
if (size) {
inh = inbufs + outbufs;
- if (!kernel)
- VERIFY(0 == copy_from_user(&rpra[inh], &upra[inh],
+ if (!kernel) {
+ VERIFY(err, 0 == copy_from_user(&rpra[inh], &upra[inh],
size));
- else
+ if (err)
+ goto bail;
+ } else {
memmove(&rpra[inh], &upra[inh], size);
+ }
}
dmac_flush_range(rpra, (char *)rpra + used);
bail:
@@ -298,24 +330,30 @@
static int put_args(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
remote_arg_t *rpra, remote_arg_t *upra)
{
- int ii, inbufs, outbufs, outh, size;
+ int i, inbufs, outbufs, outh, size;
int err = 0;
inbufs = REMOTE_SCALARS_INBUFS(sc);
outbufs = REMOTE_SCALARS_OUTBUFS(sc);
- for (ii = inbufs; ii < inbufs + outbufs; ++ii) {
- if (rpra[ii].buf.pv != pra[ii].buf.pv)
- VERIFY(0 == copy_to_user(pra[ii].buf.pv,
- rpra[ii].buf.pv, rpra[ii].buf.len));
+ for (i = inbufs; i < inbufs + outbufs; ++i) {
+ if (rpra[i].buf.pv != pra[i].buf.pv) {
+ VERIFY(err, 0 == copy_to_user(pra[i].buf.pv,
+ rpra[i].buf.pv, rpra[i].buf.len));
+ if (err)
+ goto bail;
+ }
}
size = sizeof(*rpra) * REMOTE_SCALARS_OUTHANDLES(sc);
if (size) {
outh = inbufs + outbufs + REMOTE_SCALARS_INHANDLES(sc);
- if (!kernel)
- VERIFY(0 == copy_to_user(&upra[outh], &rpra[outh],
+ if (!kernel) {
+ VERIFY(err, 0 == copy_to_user(&upra[outh], &rpra[outh],
size));
- else
+ if (err)
+ goto bail;
+ } else {
memmove(&upra[outh], &rpra[outh], size);
+ }
}
bail:
return err;
@@ -323,24 +361,24 @@
static void inv_args(uint32_t sc, remote_arg_t *rpra, int used)
{
- int ii, inbufs, outbufs;
+ int i, inbufs, outbufs;
int inv = 0;
inbufs = REMOTE_SCALARS_INBUFS(sc);
outbufs = REMOTE_SCALARS_OUTBUFS(sc);
- for (ii = inbufs; ii < inbufs + outbufs; ++ii) {
- if (buf_page_start(rpra) == buf_page_start(rpra[ii].buf.pv))
+ for (i = inbufs; i < inbufs + outbufs; ++i) {
+ if (buf_page_start(rpra) == buf_page_start(rpra[i].buf.pv))
inv = 1;
- else
- dmac_inv_range(rpra[ii].buf.pv,
- (char *)rpra[ii].buf.pv + rpra[ii].buf.len);
+ else if (rpra[i].buf.len)
+ dmac_inv_range(rpra[i].buf.pv,
+ (char *)rpra[i].buf.pv + rpra[i].buf.len);
}
if (inv || REMOTE_SCALARS_OUTHANDLES(sc))
dmac_inv_range(rpra, (char *)rpra + used);
}
-static int fastrpc_invoke_send(struct fastrpc_apps *me, remote_handle_t handle,
+static int fastrpc_invoke_send(struct fastrpc_apps *me, uint32_t handle,
uint32_t sc, struct smq_invoke_ctx *ctx,
struct fastrpc_buf *buf)
{
@@ -357,8 +395,7 @@
spin_lock(&me->wrlock);
len = smd_write(me->chan, &msg, sizeof(msg));
spin_unlock(&me->wrlock);
- VERIFY(len == sizeof(msg));
- bail:
+ VERIFY(err, len == sizeof(msg));
return err;
}
@@ -369,7 +406,8 @@
if (me->chan)
(void)smd_close(me->chan);
context_list_dtor(&me->clst);
- ion_client_destroy(me->iclient);
+ if (me->iclient)
+ ion_client_destroy(me->iclient);
me->iclient = 0;
me->chan = 0;
}
@@ -381,8 +419,10 @@
int err = 0;
do {
- VERIFY(sizeof(rsp) ==
+ VERIFY(err, sizeof(rsp) ==
smd_read_from_cb(me->chan, &rsp, sizeof(rsp)));
+ if (err)
+ goto bail;
context_notify_user(rsp.ctx, rsp.retval);
} while (!err);
bail:
@@ -412,21 +452,29 @@
struct fastrpc_apps *me = &gfa;
if (me->chan == 0) {
- int ii;
+ int i;
spin_lock_init(&me->hlock);
spin_lock_init(&me->wrlock);
init_completion(&me->work);
- for (ii = 0; ii < RPC_HASH_SZ; ++ii)
- INIT_HLIST_HEAD(&me->htbl[ii]);
- VERIFY(0 == context_list_ctor(&me->clst, SZ_4K));
+ for (i = 0; i < RPC_HASH_SZ; ++i)
+ INIT_HLIST_HEAD(&me->htbl[i]);
+ VERIFY(err, 0 == context_list_ctor(&me->clst, SZ_4K));
+ if (err)
+ goto bail;
me->iclient = msm_ion_client_create(ION_HEAP_CARVEOUT_MASK,
DEVICE_NAME);
- VERIFY(0 == IS_ERR_OR_NULL(me->iclient));
- VERIFY(0 == smd_named_open_on_edge(FASTRPC_SMD_GUID,
+ VERIFY(err, 0 == IS_ERR_OR_NULL(me->iclient));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 == smd_named_open_on_edge(FASTRPC_SMD_GUID,
SMD_APPS_QDSP, &me->chan,
me, smd_event_handler));
- VERIFY(0 != wait_for_completion_timeout(&me->work,
+ if (err)
+ goto bail;
+ VERIFY(err, 0 != wait_for_completion_timeout(&me->work,
RPC_TIMEOUT));
+ if (err)
+ goto bail;
}
bail:
if (err)
@@ -448,10 +496,16 @@
int err = 0;
struct fastrpc_device *fd = 0;
- VERIFY(0 != try_module_get(THIS_MODULE));
- VERIFY(0 != (fd = kzalloc(sizeof(*fd), GFP_KERNEL)));
+ VERIFY(err, 0 != try_module_get(THIS_MODULE));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 != (fd = kzalloc(sizeof(*fd), GFP_KERNEL)));
+ if (err)
+ goto bail;
fd->buf.size = PAGE_SIZE;
- VERIFY(0 == alloc_mem(&fd->buf));
+ VERIFY(err, 0 == alloc_mem(&fd->buf));
+ if (err)
+ goto bail;
fd->tgid = current->tgid;
INIT_HLIST_NODE(&fd->hn);
*dev = fd;
@@ -478,7 +532,9 @@
}
}
spin_unlock(&me->hlock);
- VERIFY(dev != 0);
+ VERIFY(err, dev != 0);
+ if (err)
+ goto bail;
*rdev = dev;
bail:
if (err) {
@@ -511,34 +567,49 @@
struct fastrpc_buf obuf, *abufs = 0, *b;
int interrupted = 0;
uint32_t sc;
- int ii, nbufs = 0, err = 0;
+ int i, nbufs = 0, err = 0;
sc = invoke->sc;
obuf.handle = 0;
if (REMOTE_SCALARS_LENGTH(sc)) {
- VERIFY(0 == get_dev(me, &dev));
- VERIFY(0 == get_page_list(kernel, sc, pra, &dev->buf, &obuf));
+ VERIFY(err, 0 == get_dev(me, &dev));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 == get_page_list(kernel, sc, pra, &dev->buf,
+ &obuf));
+ if (err)
+ goto bail;
rpra = (remote_arg_t *)obuf.virt;
- VERIFY(0 == get_args(kernel, sc, pra, rpra, invoke->pra, &obuf,
- &abufs, &nbufs));
+ VERIFY(err, 0 == get_args(kernel, sc, pra, rpra, invoke->pra,
+ &obuf, &abufs, &nbufs));
+ if (err)
+ goto bail;
}
context_list_alloc_ctx(&me->clst, &ctx);
- VERIFY(0 == fastrpc_invoke_send(me, invoke->handle, sc, ctx, &obuf));
+ VERIFY(err, 0 == fastrpc_invoke_send(me, invoke->handle, sc, ctx,
+ &obuf));
+ if (err)
+ goto bail;
inv_args(sc, rpra, obuf.used);
- VERIFY(0 == (interrupted =
+ VERIFY(err, 0 == (interrupted =
wait_for_completion_interruptible(&ctx->work)));
- VERIFY(0 == (err = ctx->retval));
- VERIFY(0 == put_args(kernel, sc, pra, rpra, invoke->pra));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 == (err = ctx->retval));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 == put_args(kernel, sc, pra, rpra, invoke->pra));
+ if (err)
+ goto bail;
bail:
if (interrupted) {
- init_completion(&ctx->work);
if (!kernel)
(void)fastrpc_release_current_dsp_process();
wait_for_completion(&ctx->work);
}
context_free(ctx);
- for (ii = 0, b = abufs; ii < nbufs; ++ii, ++b)
+ for (i = 0, b = abufs; i < nbufs; ++i, ++b)
free_mem(b);
kfree(abufs);
if (dev) {
@@ -563,8 +634,7 @@
ioctl.handle = 1;
ioctl.sc = REMOTE_SCALARS_MAKE(0, 1, 0);
ioctl.pra = ra;
- VERIFY(0 == fastrpc_internal_invoke(me, 1, &ioctl, ra));
- bail:
+ VERIFY(err, 0 == fastrpc_internal_invoke(me, 1, &ioctl, ra));
return err;
}
@@ -582,8 +652,7 @@
ioctl.handle = 1;
ioctl.sc = REMOTE_SCALARS_MAKE(1, 1, 0);
ioctl.pra = ra;
- VERIFY(0 == fastrpc_internal_invoke(me, 1, &ioctl, ra));
- bail:
+ VERIFY(err, 0 == fastrpc_internal_invoke(me, 1, &ioctl, ra));
return err;
}
@@ -628,8 +697,7 @@
/* This call will cause a dev to be created
* which will addref this module
*/
- VERIFY(0 == fastrpc_create_current_dsp_process());
- bail:
+ VERIFY(err, 0 == fastrpc_create_current_dsp_process());
if (err)
cleanup_current_dev();
module_put(THIS_MODULE);
@@ -649,19 +717,28 @@
switch (ioctl_num) {
case FASTRPC_IOCTL_INVOKE:
- VERIFY(0 == copy_from_user(&invoke, param, sizeof(invoke)));
+ VERIFY(err, 0 == copy_from_user(&invoke, param,
+ sizeof(invoke)));
+ if (err)
+ goto bail;
bufs = REMOTE_SCALARS_INBUFS(invoke.sc) +
REMOTE_SCALARS_OUTBUFS(invoke.sc);
if (bufs) {
bufs = bufs * sizeof(*pra);
- VERIFY(0 != (pra = kmalloc(bufs, GFP_KERNEL)));
+ VERIFY(err, 0 != (pra = kmalloc(bufs, GFP_KERNEL)));
+ if (err)
+ goto bail;
}
- VERIFY(0 == copy_from_user(pra, invoke.pra, bufs));
- VERIFY(0 == (err = fastrpc_internal_invoke(me, 0, &invoke,
+ VERIFY(err, 0 == copy_from_user(pra, invoke.pra, bufs));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 0, &invoke,
pra)));
+ if (err)
+ goto bail;
break;
default:
- err = -EINVAL;
+ err = -ENOTTY;
break;
}
bail:
@@ -680,13 +757,24 @@
struct fastrpc_apps *me = &gfa;
int err = 0;
- VERIFY(0 == fastrpc_init());
- VERIFY(0 == alloc_chrdev_region(&me->dev_no, 0, 1, DEVICE_NAME));
+ VERIFY(err, 0 == fastrpc_init());
+ if (err)
+ goto bail;
+ VERIFY(err, 0 == alloc_chrdev_region(&me->dev_no, 0, 1, DEVICE_NAME));
+ if (err)
+ goto bail;
cdev_init(&me->cdev, &fops);
me->cdev.owner = THIS_MODULE;
- VERIFY(0 == cdev_add(&me->cdev, MKDEV(MAJOR(me->dev_no), 0), 1));
+ VERIFY(err, 0 == cdev_add(&me->cdev, MKDEV(MAJOR(me->dev_no), 0), 1));
+ if (err)
+ goto bail;
pr_info("'mknod /dev/%s c %d 0'\n", DEVICE_NAME, MAJOR(me->dev_no));
bail:
+ if (err) {
+ if (me->dev_no)
+ unregister_chrdev_region(me->dev_no, 1);
+ fastrpc_deinit();
+ }
return err;
}
diff --git a/arch/arm/mach-msm/qdsp6v2/adsprpc.h b/arch/arm/mach-msm/qdsp6v2/adsprpc.h
index c6c7d23..3f1b4a7 100644
--- a/arch/arm/mach-msm/qdsp6v2/adsprpc.h
+++ b/arch/arm/mach-msm/qdsp6v2/adsprpc.h
@@ -36,8 +36,7 @@
#define RPC_TIMEOUT (5 * HZ)
#define RPC_HASH_BITS 5
#define RPC_HASH_SZ (1 << RPC_HASH_BITS)
-
-#define ALIGN_8(a) ALIGN(a, 8)
+#define BALIGN 32
#define LOCK_MMAP(kernel)\
do {\
@@ -84,18 +83,26 @@
struct vm_area_struct *vma;
uint32_t start = buf_page_start(addr);
uint32_t len = nr_pages << PAGE_SHIFT;
- uint32_t pfn;
+ unsigned long pfn;
int n = -1, err = 0;
- VERIFY(0 != access_ok(access ? VERIFY_WRITE : VERIFY_READ,
+ VERIFY(err, 0 != access_ok(access ? VERIFY_WRITE : VERIFY_READ,
(void __user *)start, len));
- VERIFY(0 != (vma = find_vma(current->mm, start)));
- VERIFY(((uint32_t)addr + sz) <= vma->vm_end);
+ if (err)
+ goto bail;
+ VERIFY(err, 0 != (vma = find_vma(current->mm, start)));
+ if (err)
+ goto bail;
+ VERIFY(err, ((uint32_t)addr + sz) <= vma->vm_end);
+ if (err)
+ goto bail;
n = 0;
- VERIFY(0 != (vma->vm_flags & VM_PFNMAP));
- VERIFY(0 != (vma->vm_flags & VM_PFN_AT_MMAP));
- VERIFY(nr_elems > 0);
- pfn = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
+ VERIFY(err, 0 == follow_pfn(vma, start, &pfn));
+ if (err)
+ goto bail;
+ VERIFY(err, nr_elems > 0);
+ if (err)
+ goto bail;
pages->addr = __pfn_to_phys(pfn);
pages->size = len;
n++;
diff --git a/arch/arm/mach-msm/qdsp6v2/adsprpc_shared.h b/arch/arm/mach-msm/qdsp6v2/adsprpc_shared.h
index 04b1d4a..dc6ab6f 100644
--- a/arch/arm/mach-msm/qdsp6v2/adsprpc_shared.h
+++ b/arch/arm/mach-msm/qdsp6v2/adsprpc_shared.h
@@ -60,20 +60,18 @@
#define __TOSTR__(x) __STR__(x)
#define __FILE_LINE__ __FILE__ ":" __TOSTR__(__LINE__)
-#define VERIFY(val) \
+#define VERIFY(err, val) \
do {\
VERIFY_IPRINTF(__FILE_LINE__"info: calling: " #val "\n");\
if (0 == (val)) {\
- err = err == 0 ? -1 : err;\
- VERIFY_EPRINTF(__FILE_LINE__"error: %d: " #val "\n", err);\
- goto bail;\
+ (err) = (err) == 0 ? -1 : (err);\
+ VERIFY_EPRINTF(__FILE_LINE__"error: %d: " #val "\n", (err));\
} else {\
VERIFY_IPRINTF(__FILE_LINE__"info: passed: " #val "\n");\
} \
} while (0)
#endif
-#define remote_handle_t uint32_t
#define remote_arg_t union remote_arg
struct remote_buf {
@@ -83,18 +81,18 @@
union remote_arg {
struct remote_buf buf; /* buffer info */
- remote_handle_t h; /* remote handle */
+ uint32_t h; /* remote handle */
};
struct fastrpc_ioctl_invoke {
- remote_handle_t handle; /* remote handle */
+ uint32_t handle; /* remote handle */
uint32_t sc; /* scalars describing the data */
remote_arg_t *pra; /* remote arguments list */
};
struct smq_null_invoke {
struct smq_invoke_ctx *ctx; /* invoke caller context */
- remote_handle_t handle; /* handle to invoke */
+ uint32_t handle; /* handle to invoke */
uint32_t sc; /* scalars structure describing the data */
};
diff --git a/arch/arm/mach-msm/qdsp6v2/pcm_in_proxy.c b/arch/arm/mach-msm/qdsp6v2/pcm_in_proxy.c
new file mode 100644
index 0000000..84f136a
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/pcm_in_proxy.c
@@ -0,0 +1,596 @@
+
+/* Copyright (c) 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 and
+* only version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*/
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/msm_audio.h>
+
+#include <asm/atomic.h>
+#include <mach/debug_mm.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include <sound/q6asm.h>
+#include <sound/apr_audio.h>
+#include <linux/wakelock.h>
+#include <mach/cpuidle.h>
+
+#define MAX_BUF 4
+
+struct dma_buf {
+ uint32_t addr;
+ uint32_t v_addr;
+ uint32_t used;
+};
+struct pcm {
+ struct mutex lock;
+ struct mutex read_lock;
+ wait_queue_head_t wait;
+ spinlock_t dsp_lock;
+ struct audio_client *ac;
+ uint32_t sample_rate;
+ uint32_t channel_count;
+ uint32_t buffer_size;
+ uint32_t buffer_count;
+ uint32_t cpu_idx;
+ uint32_t dsp_idx;
+ uint32_t start;
+ uint32_t dma_addr;
+ uint32_t dma_virt;
+ struct dma_buf dma_buf[MAX_BUF];
+ atomic_t in_count;
+ atomic_t in_enabled;
+ atomic_t in_opened;
+ atomic_t in_stopped;
+ int poll_time;
+ struct hrtimer hrt;
+};
+
+static enum hrtimer_restart afe_hrtimer_callback(struct hrtimer *hrt);
+
+static enum hrtimer_restart afe_hrtimer_callback(struct hrtimer *hrt)
+{
+ struct pcm *pcm =
+ container_of(hrt, struct pcm, hrt);
+ int rc = 0;
+ if (pcm->start) {
+ if (pcm->dsp_idx == pcm->buffer_count)
+ pcm->dsp_idx = 0;
+ rc = wait_event_timeout(pcm->wait,
+ (pcm->dma_buf[pcm->dsp_idx].used == 0) ||
+ atomic_read(&pcm->in_stopped), 1 * HZ);
+ if (!rc) {
+ pr_err("%s: wait_event_timeout failed\n", __func__);
+ goto fail;
+ }
+ if (atomic_read(&pcm->in_stopped)) {
+ pr_err("%s: Driver closed - return\n", __func__);
+ return HRTIMER_NORESTART;
+ }
+ rc = afe_rt_proxy_port_read(
+ pcm->dma_buf[pcm->dsp_idx].addr,
+ pcm->buffer_size);
+ if (rc < 0) {
+ pr_err("%s afe_rt_proxy_port_read fail\n", __func__);
+ goto fail;
+ }
+ pcm->dma_buf[pcm->dsp_idx].used = 1;
+ pcm->dsp_idx++;
+ pr_debug("%s: sending frame rec to DSP: poll_time: %d\n",
+ __func__, pcm->poll_time);
+fail:
+ hrtimer_forward_now(hrt, ns_to_ktime(pcm->poll_time
+ * 1000));
+
+ return HRTIMER_RESTART;
+ } else {
+ return HRTIMER_NORESTART;
+ }
+}
+
+static void pcm_afe_callback(uint32_t opcode,
+ uint32_t token, uint32_t *payload,
+ void *priv)
+{
+ struct pcm *pcm = (struct pcm *)priv;
+ unsigned long dsp_flags;
+ uint16_t event;
+
+ if (pcm == NULL)
+ return;
+ pr_debug("%s\n", __func__);
+ spin_lock_irqsave(&pcm->dsp_lock, dsp_flags);
+ switch (opcode) {
+ case AFE_EVENT_RT_PROXY_PORT_STATUS: {
+ event = (uint16_t)((0xFFFF0000 & payload[0]) >> 0x10);
+ switch (event) {
+ case AFE_EVENT_RTPORT_START: {
+ pcm->dsp_idx = 0;
+ pcm->cpu_idx = 0;
+ pcm->poll_time = (unsigned long)
+ (((pcm->buffer_size*1000)/
+ (pcm->channel_count *
+ pcm->sample_rate * 2))*1000);
+ pr_debug("%s: poll_time:%d\n", __func__,
+ pcm->poll_time);
+ pcm->start = 1;
+ wake_up(&pcm->wait);
+ break;
+ }
+ case AFE_EVENT_RTPORT_STOP:
+ pr_debug("%s: event!=0\n", __func__);
+ pcm->start = 0;
+ atomic_set(&pcm->in_stopped, 1);
+ break;
+ case AFE_EVENT_RTPORT_LOW_WM:
+ pr_debug("%s: Underrun\n", __func__);
+ break;
+ case AFE_EVENT_RTPORT_HI_WM:
+ pr_debug("%s: Overrun\n", __func__);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case APR_BASIC_RSP_RESULT: {
+ switch (payload[0]) {
+ case AFE_SERVICE_CMD_RTPORT_RD:
+ pr_debug("%s: Read done\n", __func__);
+ atomic_inc(&pcm->in_count);
+ wake_up(&pcm->wait);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ spin_unlock_irqrestore(&pcm->dsp_lock, dsp_flags);
+}
+
+static uint32_t getbuffersize(uint32_t samplerate)
+{
+ if (samplerate == 8000)
+ return 480*8;
+ else if (samplerate == 16000)
+ return 480*16;
+ else if (samplerate == 48000)
+ return 480*48;
+ return 0;
+}
+
+static int pcm_in_open(struct inode *inode, struct file *file)
+{
+ struct pcm *pcm;
+ int rc = 0;
+
+ pr_debug("%s: pcm proxy in open session\n", __func__);
+ pcm = kzalloc(sizeof(struct pcm), GFP_KERNEL);
+ if (!pcm)
+ return -ENOMEM;
+
+ pcm->channel_count = 1;
+ pcm->sample_rate = 8000;
+ pcm->buffer_size = getbuffersize(pcm->sample_rate);
+ pcm->buffer_count = MAX_BUF;
+
+ pcm->ac = q6asm_audio_client_alloc(NULL, (void *)pcm);
+ if (!pcm->ac) {
+ pr_err("%s: Could not allocate memory\n", __func__);
+ rc = -ENOMEM;
+ goto fail;
+ }
+
+ mutex_init(&pcm->lock);
+ mutex_init(&pcm->read_lock);
+ spin_lock_init(&pcm->dsp_lock);
+ init_waitqueue_head(&pcm->wait);
+
+ hrtimer_init(&pcm->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ pcm->hrt.function = afe_hrtimer_callback;
+
+ atomic_set(&pcm->in_stopped, 0);
+ atomic_set(&pcm->in_enabled, 0);
+ atomic_set(&pcm->in_count, 0);
+ atomic_set(&pcm->in_opened, 1);
+
+ file->private_data = pcm;
+ pr_debug("%s: pcm proxy open success session id:%d\n",
+ __func__, pcm->ac->session);
+ return 0;
+fail:
+ if (pcm->ac)
+ q6asm_audio_client_free(pcm->ac);
+ kfree(pcm);
+ return rc;
+}
+
+static int pcm_in_disable(struct pcm *pcm)
+{
+ int rc = 0;
+
+ if (atomic_read(&pcm->in_opened)) {
+ atomic_set(&pcm->in_enabled, 0);
+ atomic_set(&pcm->in_opened, 0);
+ atomic_set(&pcm->in_stopped, 1);
+ wake_up(&pcm->wait);
+ }
+ return rc;
+}
+
+static int config(struct pcm *pcm)
+{
+
+ int ret = 0, i;
+ struct audio_buffer *buf;
+
+ pr_debug("%s\n", __func__);
+
+ ret = q6asm_audio_client_buf_alloc_contiguous(OUT,
+ pcm->ac,
+ pcm->buffer_size,
+ pcm->buffer_count);
+ if (ret < 0) {
+ pr_err("%s: Audio Start: Buffer Allocation failed rc = %d\n",
+ __func__, ret);
+ return -ENOMEM;
+ }
+ buf = pcm->ac->port[OUT].buf;
+
+ if (buf == NULL || buf[0].data == NULL)
+ return -ENOMEM;
+
+ memset(buf[0].data, 0, pcm->buffer_size * pcm->buffer_count);
+ pcm->dma_addr = (u32) buf[0].phys;
+ pcm->dma_virt = (u32) buf[0].data;
+
+ for (i = 0; i < pcm->buffer_count; i++) {
+ pcm->dma_buf[i].addr = (u32) (buf[i].phys);
+ pcm->dma_buf[i].v_addr = (u32) (buf[i].data);
+ pcm->dma_buf[i].used = 0;
+ }
+
+ ret = afe_register_get_events(RT_PROXY_DAI_001_TX,
+ pcm_afe_callback, pcm);
+ if (ret < 0) {
+ pr_err("%s: afe-pcm:register for events failed\n", __func__);
+ return ret;
+ }
+ ret = afe_cmd_memory_map(pcm->dma_addr,
+ pcm->buffer_size * pcm->buffer_count);
+ if (ret < 0) {
+ pr_err("%s: fail to map memory to DSP\n", __func__);
+ return ret;
+ }
+
+ pr_debug("%s:success\n", __func__);
+ return ret;
+}
+static bool is_dma_buf_avail(struct pcm *pcm)
+{
+ return (pcm->dma_buf[pcm->cpu_idx].used == 1);
+}
+static ssize_t pcm_in_read(struct file *file, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct pcm *pcm = file->private_data;
+ const char __user *start = buf;
+ int rc = 0;
+ bool rc1 = false;
+ int len = 0;
+
+ if (!atomic_read(&pcm->in_enabled))
+ return -EFAULT;
+ mutex_lock(&pcm->read_lock);
+ while (count > 0) {
+ rc = wait_event_timeout(pcm->wait,
+ (atomic_read(&pcm->in_count) ||
+ atomic_read(&pcm->in_stopped)), 2 * HZ);
+ if (!rc) {
+ pr_err("%s: wait_event_timeout failed\n", __func__);
+ goto fail;
+ }
+ if (atomic_read(&pcm->in_stopped) &&
+ !atomic_read(&pcm->in_count)) {
+ pr_err("%s: count:%d/stopped:%d failed\n", __func__,
+ atomic_read(&pcm->in_count),
+ atomic_read(&pcm->in_stopped));
+ mutex_unlock(&pcm->read_lock);
+ return 0;
+ }
+
+ rc1 = is_dma_buf_avail(pcm);
+ if (!rc1) {
+ pr_err("%s: DMA buf not ready-returning from read\n",
+ __func__);
+ goto fail;
+ }
+ if (count >= pcm->buffer_size)
+ len = pcm->buffer_size;
+ else {
+ len = count;
+ pr_err("%s: short bytesavail[%d]"\
+ "bytesrequest[%d]"\
+ "bytesrejected%d]\n",\
+ __func__, pcm->buffer_size,
+ count, (pcm->buffer_size - count));
+ }
+ if (len) {
+ if (copy_to_user(buf,
+ (char *)(pcm->dma_buf[pcm->cpu_idx].v_addr),
+ len)) {
+ pr_err("%s copy_to_user failed len[%d]\n",
+ __func__, len);
+ rc = -EFAULT;
+ goto fail;
+ }
+ count -= len;
+ buf += len;
+ }
+ atomic_dec(&pcm->in_count);
+ memset((char *)(pcm->dma_buf[pcm->cpu_idx].v_addr),
+ 0, pcm->buffer_size);
+ pcm->dma_buf[pcm->cpu_idx].used = 0;
+ wake_up(&pcm->wait);
+ pcm->cpu_idx++;
+ if (pcm->cpu_idx == pcm->buffer_count)
+ pcm->cpu_idx = 0;
+
+ }
+ rc = buf-start;
+ pr_debug("%s: pcm_in_read:rc:%d\n", __func__, rc);
+
+fail:
+ mutex_unlock(&pcm->read_lock);
+ return rc;
+}
+
+static int afe_start(struct pcm *pcm)
+{
+ union afe_port_config port_config;
+ port_config.rtproxy.num_ch =
+ pcm->channel_count;
+
+ pr_debug("%s: channel %d entered,port: %d,rate: %d\n", __func__,
+ port_config.rtproxy.num_ch, RT_PROXY_DAI_001_TX, pcm->sample_rate);
+
+ port_config.rtproxy.bitwidth = 16; /* Q6 only supports 16 */
+ port_config.rtproxy.interleaved = 1;
+ port_config.rtproxy.frame_sz = pcm->buffer_size;
+ port_config.rtproxy.jitter =
+ port_config.rtproxy.frame_sz/2;
+ port_config.rtproxy.lw_mark = 0;
+ port_config.rtproxy.hw_mark = 0;
+ port_config.rtproxy.rsvd = 0;
+ afe_open(RT_PROXY_DAI_001_TX, &port_config, pcm->sample_rate);
+ return 0;
+
+}
+
+static long pcm_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct pcm *pcm = file->private_data;
+ int rc = 0;
+
+ mutex_lock(&pcm->lock);
+ switch (cmd) {
+ case AUDIO_START: {
+ pr_debug("%s: AUDIO_START\n", __func__);
+ if (atomic_read(&pcm->in_enabled)) {
+ pr_info("%s:AUDIO_START already over\n", __func__);
+ rc = 0;
+ break;
+ }
+ rc = config(pcm);
+ if (rc) {
+ pr_err("%s: IN Configuration failed\n", __func__);
+ rc = -EFAULT;
+ break;
+ }
+ pr_debug("%s: call config done\n", __func__);
+ atomic_set(&pcm->in_enabled, 1);
+ afe_start(pcm);
+ rc = wait_event_timeout(pcm->wait,
+ ((pcm->start == 1) ||
+ atomic_read(&pcm->in_stopped)), 5 * HZ);
+ if (!rc) {
+ pr_err("%s: wait_event_timeout failed\n", __func__);
+ goto fail;
+ }
+ pr_debug("%s: afe start done\n", __func__);
+ if (atomic_read(&pcm->in_stopped)) {
+ pr_err("%s: stopped unexpected before start!!\n",
+ __func__);
+ mutex_unlock(&pcm->lock);
+ return 0;
+ }
+
+ hrtimer_start(&pcm->hrt, ns_to_ktime(0),
+ HRTIMER_MODE_REL);
+ break;
+ }
+ case AUDIO_STOP:
+ break;
+ case AUDIO_FLUSH:
+ break;
+ case AUDIO_SET_CONFIG: {
+ struct msm_audio_config config;
+
+ if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+ rc = -EFAULT;
+ break;
+ }
+ pr_debug("%s: SET_CONFIG: channel_count:%d"\
+ "sample_rate:%d\n", __func__,
+ config.channel_count,
+ config.sample_rate);
+
+ if (!config.channel_count || config.channel_count > 2) {
+ pr_err("%s: Channels(%d) not supported\n",
+ __func__, config.channel_count);
+ rc = -EINVAL;
+ break;
+ }
+
+ if (config.sample_rate != 8000 &&
+ config.sample_rate != 16000 &&
+ config.sample_rate != 48000) {
+ pr_err("%s: Sample rate(%d) not supported\n",
+ __func__, config.sample_rate);
+ rc = -EINVAL;
+ break;
+ }
+
+ pcm->sample_rate = config.sample_rate;
+ pcm->channel_count = config.channel_count;
+ pcm->buffer_size = getbuffersize(pcm->sample_rate);
+
+ pr_debug("%s: Calculated buff size %d", __func__,
+ pcm->buffer_size);
+ break;
+ }
+ case AUDIO_GET_CONFIG: {
+ struct msm_audio_config config;
+ config.buffer_size = pcm->buffer_size;
+ config.buffer_count = pcm->buffer_count;
+ config.sample_rate = pcm->sample_rate;
+ config.channel_count = pcm->channel_count;
+ config.unused[0] = 0;
+ config.unused[1] = 0;
+ config.unused[2] = 0;
+ if (copy_to_user((void *) arg, &config, sizeof(config)))
+ rc = -EFAULT;
+ break;
+ }
+ case AUDIO_PAUSE:
+ pr_debug("%s: AUDIO_PAUSE %ld\n", __func__, arg);
+ if (arg == 1) {
+ pcm->start = 0;
+ } else if (arg == 0) {
+ pcm->start = 1;
+ hrtimer_start(&pcm->hrt, ns_to_ktime(0),
+ HRTIMER_MODE_REL);
+ }
+ break;
+
+ default:
+ rc = -EINVAL;
+ break;
+ }
+fail:
+ mutex_unlock(&pcm->lock);
+ return rc;
+}
+
+static int pcm_in_release(struct inode *inode, struct file *file)
+{
+ int rc = 0;
+ struct pcm *pcm = file->private_data;
+
+ pr_debug("[%s:%s] release session id[%d]\n", __MM_FILE__,
+ __func__, pcm->ac->session);
+ mutex_lock(&pcm->lock);
+
+
+ /* remove this session from topology list */
+ auddev_cfg_tx_copp_topology(pcm->ac->session,
+ DEFAULT_COPP_TOPOLOGY);
+
+ rc = pcm_in_disable(pcm);
+ hrtimer_cancel(&pcm->hrt);
+ rc = afe_cmd_memory_unmap(pcm->dma_addr);
+ if (rc < 0)
+ pr_err("%s: AFE memory unmap failed\n", __func__);
+ rc = afe_unregister_get_events(RT_PROXY_DAI_001_TX);
+ if (rc < 0)
+ pr_err("%s: AFE unregister for events failed\n", __func__);
+
+ afe_close(RT_PROXY_DAI_001_TX);
+ pr_debug("%s: release all buffer\n", __func__);
+ q6asm_audio_client_buf_free_contiguous(OUT,
+ pcm->ac);
+ msm_clear_session_id(pcm->ac->session);
+ q6asm_audio_client_free(pcm->ac);
+ mutex_unlock(&pcm->lock);
+ mutex_destroy(&pcm->lock);
+ mutex_destroy(&pcm->read_lock);
+ kfree(pcm);
+ return rc;
+}
+
+static const struct file_operations pcm_in_proxy_fops = {
+ .owner = THIS_MODULE,
+ .open = pcm_in_open,
+ .read = pcm_in_read,
+ .release = pcm_in_release,
+ .unlocked_ioctl = pcm_in_ioctl,
+};
+
+struct miscdevice pcm_in_proxy_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_pcm_in_proxy",
+ .fops = &pcm_in_proxy_fops,
+};
+
+static int snddev_rtproxy_open(struct msm_snddev_info *dev_info)
+{
+ return 0;
+}
+
+static int snddev_rtproxy_close(struct msm_snddev_info *dev_info)
+{
+ return 0;
+}
+
+static int snddev_rtproxy_set_freq(struct msm_snddev_info *dev_info,
+ u32 req_freq)
+{
+ return 48000;
+}
+
+static int __init pcm_in_proxy_init(void)
+{
+ struct msm_snddev_info *dev_info;
+
+ dev_info = kzalloc(sizeof(struct msm_snddev_info), GFP_KERNEL);
+ if (!dev_info) {
+ pr_err("unable to allocate memeory for msm_snddev_info\n");
+ return -ENOMEM;
+ }
+ dev_info->name = "rtproxy_rx";
+ dev_info->copp_id = RT_PROXY_PORT_001_RX;
+ dev_info->acdb_id = 0;
+ dev_info->private_data = NULL;
+ dev_info->dev_ops.open = snddev_rtproxy_open;
+ dev_info->dev_ops.close = snddev_rtproxy_close;
+ dev_info->dev_ops.set_freq = snddev_rtproxy_set_freq;
+ dev_info->capability = SNDDEV_CAP_RX;
+ dev_info->opened = 0;
+ msm_snddev_register(dev_info);
+ dev_info->sample_rate = 48000;
+
+ pr_debug("%s: init done for proxy\n", __func__);
+
+ return misc_register(&pcm_in_proxy_misc);
+}
+
+device_initcall(pcm_in_proxy_init);
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
index 2189747..7966177 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -228,6 +228,7 @@
}
flush_cache_all();
+ outer_flush_all();
}
void msm_restart(char mode, const char *cmd)
diff --git a/drivers/hwmon/epm_adc.c b/drivers/hwmon/epm_adc.c
index 368aac4..69a2f1c 100644
--- a/drivers/hwmon/epm_adc.c
+++ b/drivers/hwmon/epm_adc.c
@@ -1703,7 +1703,7 @@
}
static const struct of_device_id epm_adc_psoc_match_table[] = {
- { .compatible = "qcom,epm-adc",
+ { .compatible = "cy,epm-adc-cy8c5568lti-114",
},
{}
};
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index aa375d7..0a85b93 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -111,6 +111,13 @@
#define QPNP_DATA1 0x61
#define QPNP_CONV_TIMEOUT_ERR 2
+#define QPNP_IADC_SEC_ACCESS 0xD0
+#define QPNP_IADC_SEC_ACCESS_DATA 0xA5
+#define QPNP_IADC_MSB_OFFSET 0xF2
+#define QPNP_IADC_LSB_OFFSET 0xF3
+#define QPNP_IADC_NOMINAL_RSENSE 0xF4
+#define QPNP_IADC_ATE_GAIN_CALIB_OFFSET 0xF5
+
#define QPNP_IADC_ADC_CH_SEL_CTL 0x48
#define QPNP_IADC_ADC_CHX_SEL_SHIFT 3
@@ -127,15 +134,27 @@
#define QPNP_ADC_CONV_TIME_MIN 8000
#define QPNP_ADC_CONV_TIME_MAX 8200
-#define QPNP_ADC_GAIN_CALCULATION_UV 17857
-#define QPNP_IADC_RSENSE_MILLI_FACTOR 1000
+#define QPNP_ADC_GAIN_NV 17857
+#define QPNP_OFFSET_CALIBRATION_SHORT_CADC_LEADS_IDEAL 0
+#define QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR 10000000
+#define QPNP_IADC_NANO_VOLTS_FACTOR 1000000000
+#define QPNP_IADC_CALIB_SECONDS 300000
+#define QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT 15625
+#define QPNP_IADC_DIE_TEMP_CALIB_OFFSET 5000
+
+#define QPNP_RAW_CODE_16_BIT_MSB_MASK 0xff00
+#define QPNP_RAW_CODE_16_BIT_LSB_MASK 0xff
+#define QPNP_BIT_SHIFT_8 8
+#define QPNP_RSENSE_MSB_SIGN_CHECK 0x80
struct qpnp_iadc_drv {
- struct qpnp_adc_drv *adc;
- int32_t rsense;
- struct device *iadc_hwmon;
- bool iadc_init_calib;
- bool iadc_initialized;
+ struct qpnp_adc_drv *adc;
+ int32_t rsense;
+ struct device *iadc_hwmon;
+ bool iadc_init_calib;
+ bool iadc_initialized;
+ int64_t die_temp_calib_offset;
+ struct delayed_work iadc_work;
struct sensor_device_attribute sens_attr[0];
};
@@ -253,9 +272,10 @@
return 0;
}
-static int32_t qpnp_iadc_read_conversion_result(int32_t *data)
+static int32_t qpnp_iadc_read_conversion_result(uint16_t *data)
{
uint8_t rslt_lsb, rslt_msb;
+ uint16_t rslt;
int32_t rc;
rc = qpnp_iadc_read_reg(QPNP_IADC_DATA0, &rslt_lsb);
@@ -270,16 +290,18 @@
return rc;
}
- *data = (rslt_msb << 8) | rslt_lsb;
+ rslt = (rslt_msb << 8) | rslt_lsb;
+ *data = rslt;
rc = qpnp_iadc_enable(false);
if (rc)
return rc;
+
return 0;
}
static int32_t qpnp_iadc_configure(enum qpnp_iadc_channels channel,
- int32_t *result)
+ uint16_t *raw_code)
{
struct qpnp_iadc_drv *iadc = qpnp_iadc;
u8 qpnp_iadc_mode_reg = 0, qpnp_iadc_ch_sel_reg = 0;
@@ -346,7 +368,7 @@
wait_for_completion(&iadc->adc->adc_rslt_completion);
- rc = qpnp_iadc_read_conversion_result(result);
+ rc = qpnp_iadc_read_conversion_result(raw_code);
if (rc) {
pr_err("qpnp adc read adc failed with %d\n", rc);
return rc;
@@ -355,32 +377,109 @@
return 0;
}
-static int32_t qpnp_iadc_init_calib(void)
+static int32_t qpnp_convert_raw_offset_voltage(void)
{
struct qpnp_iadc_drv *iadc = qpnp_iadc;
- int32_t rc = 0, result;
+ uint32_t num = 0;
- rc = qpnp_iadc_configure(GAIN_CALIBRATION_25MV, &result);
+ num = iadc->adc->calib.offset_raw - iadc->adc->calib.offset_raw;
+
+ iadc->adc->calib.offset_uv = (num * QPNP_ADC_GAIN_NV)/
+ (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
+
+ num = iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw;
+
+ iadc->adc->calib.gain_uv = (num * QPNP_ADC_GAIN_NV)/
+ (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
+
+ return 0;
+}
+
+static int32_t qpnp_iadc_calibrate_for_trim(void)
+{
+ struct qpnp_iadc_drv *iadc = qpnp_iadc;
+ uint8_t rslt_lsb, rslt_msb;
+ int32_t rc = 0;
+ uint16_t raw_data;
+
+ rc = qpnp_iadc_configure(GAIN_CALIBRATION_17P857MV, &raw_data);
if (rc < 0) {
pr_err("qpnp adc result read failed with %d\n", rc);
goto fail;
}
- iadc->adc->calib.gain = result;
+ iadc->adc->calib.gain_raw = raw_data;
rc = qpnp_iadc_configure(OFFSET_CALIBRATION_SHORT_CADC_LEADS,
- &result);
+ &raw_data);
if (rc < 0) {
pr_err("qpnp adc result read failed with %d\n", rc);
goto fail;
}
- iadc->adc->calib.offset = result;
+ iadc->adc->calib.offset_raw = raw_data;
+ if (rc < 0) {
+ pr_err("qpnp adc offset/gain calculation failed\n");
+ goto fail;
+ }
+ rc = qpnp_convert_raw_offset_voltage();
+
+ rslt_msb = (raw_data & QPNP_RAW_CODE_16_BIT_MSB_MASK) >>
+ QPNP_BIT_SHIFT_8;
+ rslt_lsb = raw_data & QPNP_RAW_CODE_16_BIT_LSB_MASK;
+
+ rc = qpnp_iadc_write_reg(QPNP_IADC_SEC_ACCESS,
+ QPNP_IADC_SEC_ACCESS_DATA);
+ if (rc < 0) {
+ pr_err("qpnp iadc configure error for sec access\n");
+ goto fail;
+ }
+
+ rc = qpnp_iadc_write_reg(QPNP_IADC_MSB_OFFSET,
+ rslt_msb);
+ if (rc < 0) {
+ pr_err("qpnp iadc configure error for MSB write\n");
+ goto fail;
+ }
+
+ rc = qpnp_iadc_write_reg(QPNP_IADC_SEC_ACCESS,
+ QPNP_IADC_SEC_ACCESS_DATA);
+ if (rc < 0) {
+ pr_err("qpnp iadc configure error for sec access\n");
+ goto fail;
+ }
+
+ rc = qpnp_iadc_write_reg(QPNP_IADC_LSB_OFFSET,
+ rslt_lsb);
+ if (rc < 0) {
+ pr_err("qpnp iadc configure error for LSB write\n");
+ goto fail;
+ }
fail:
return rc;
}
+static void qpnp_iadc_work(struct work_struct *work)
+{
+ struct qpnp_iadc_drv *iadc = qpnp_iadc;
+ int rc = 0;
+
+ mutex_lock(&iadc->adc->adc_lock);
+
+ rc = qpnp_iadc_calibrate_for_trim();
+ if (rc)
+ pr_err("periodic IADC calibration failed\n");
+
+ mutex_unlock(&iadc->adc->adc_lock);
+
+ schedule_delayed_work(&iadc->iadc_work,
+ round_jiffies_relative(msecs_to_jiffies
+ (QPNP_IADC_CALIB_SECONDS)));
+
+ return;
+}
+
static int32_t qpnp_iadc_version_check(void)
{
uint8_t revision;
@@ -411,40 +510,102 @@
}
EXPORT_SYMBOL(qpnp_iadc_is_ready);
-int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
- int32_t *result)
+int32_t qpnp_iadc_get_rsense(int32_t *rsense)
+{
+ uint8_t rslt_rsense;
+ int32_t rc, sign_bit = 0;
+
+ rc = qpnp_iadc_read_reg(QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense);
+ if (rc < 0) {
+ pr_err("qpnp adc rsense read failed with %d\n", rc);
+ return rc;
+ }
+
+ if (rslt_rsense & QPNP_RSENSE_MSB_SIGN_CHECK)
+ sign_bit = 1;
+
+ rslt_rsense &= ~QPNP_RSENSE_MSB_SIGN_CHECK;
+
+ if (sign_bit)
+ *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR -
+ (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
+ else
+ *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR +
+ (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
+
+ return rc;
+}
+
+int32_t qpnp_check_pmic_temp(void)
{
struct qpnp_iadc_drv *iadc = qpnp_iadc;
- int32_t vsense_mv = 0, rc;
+ struct qpnp_vadc_result result_pmic_therm;
+ int rc;
+
+ rc = qpnp_vadc_read(DIE_TEMP, &result_pmic_therm);
+ if (rc < 0)
+ return rc;
+
+ if (((uint64_t) (result_pmic_therm.physical -
+ iadc->die_temp_calib_offset))
+ > QPNP_IADC_DIE_TEMP_CALIB_OFFSET) {
+ mutex_lock(&iadc->adc->adc_lock);
+
+ rc = qpnp_iadc_calibrate_for_trim();
+ if (rc)
+ pr_err("periodic IADC calibration failed\n");
+
+ mutex_unlock(&iadc->adc->adc_lock);
+ }
+
+ return 0;
+}
+
+int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
+ struct qpnp_iadc_result *result)
+{
+ struct qpnp_iadc_drv *iadc = qpnp_iadc;
+ int32_t rc, rsense_n_ohms, sign = 0, num;
+ int64_t result_current;
+ uint16_t raw_data;
if (!iadc || !iadc->iadc_initialized)
return -EPROBE_DEFER;
- mutex_lock(&iadc->adc->adc_lock);
-
- if (!iadc->iadc_init_calib) {
- rc = qpnp_iadc_version_check();
- if (rc)
- goto fail;
- rc = qpnp_iadc_init_calib();
- if (rc) {
- pr_err("Calibration failed\n");
- goto fail;
- } else
- iadc->iadc_init_calib = true;
+ rc = qpnp_check_pmic_temp();
+ if (rc) {
+ pr_err("Error checking pmic therm temp\n");
+ return rc;
}
- rc = qpnp_iadc_configure(channel, result);
+ mutex_lock(&iadc->adc->adc_lock);
+
+ rc = qpnp_iadc_configure(channel, &raw_data);
if (rc < 0) {
pr_err("qpnp adc result read failed with %d\n", rc);
goto fail;
}
- *result = ((vsense_mv - iadc->adc->calib.offset) *
- QPNP_ADC_GAIN_CALCULATION_UV)/
- (iadc->adc->calib.gain - iadc->adc->calib.offset);
+ rc = qpnp_iadc_get_rsense(&rsense_n_ohms);
- *result = (*result / (qpnp_iadc->rsense));
+ num = raw_data - iadc->adc->calib.offset_raw;
+ if (num < 0) {
+ sign = 1;
+ num = -num;
+ }
+
+ result->result_uv = (num * QPNP_ADC_GAIN_NV)/
+ (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
+ result_current = result->result_uv;
+ result_current *= QPNP_IADC_NANO_VOLTS_FACTOR;
+ do_div(result_current, rsense_n_ohms);
+
+ if (sign) {
+ result->result_uv = -result->result_uv;
+ result_current = -result_current;
+ }
+
+ result->result_ua = (int32_t) result_current;
fail:
mutex_unlock(&iadc->adc->adc_lock);
@@ -452,24 +613,39 @@
}
EXPORT_SYMBOL(qpnp_iadc_read);
-int32_t qpnp_iadc_get_gain(int32_t *result)
+int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_calib *result)
{
- return qpnp_iadc_read(GAIN_CALIBRATION_25MV, result);
-}
-EXPORT_SYMBOL(qpnp_iadc_get_gain);
+ struct qpnp_iadc_drv *iadc = qpnp_iadc;
+ int rc;
-int32_t qpnp_iadc_get_offset(enum qpnp_iadc_channels channel,
- int32_t *result)
-{
- return qpnp_iadc_read(channel, result);
+ if (!iadc || !iadc->iadc_initialized)
+ return -EPROBE_DEFER;
+
+ rc = qpnp_check_pmic_temp();
+ if (rc) {
+ pr_err("Error checking pmic therm temp\n");
+ return rc;
+ }
+
+ mutex_lock(&iadc->adc->adc_lock);
+ result->gain_raw = iadc->adc->calib.gain_raw;
+ result->ideal_gain_nv = QPNP_ADC_GAIN_NV;
+ result->gain_uv = iadc->adc->calib.gain_uv;
+ result->offset_raw = iadc->adc->calib.offset_raw;
+ result->ideal_offset_uv =
+ QPNP_OFFSET_CALIBRATION_SHORT_CADC_LEADS_IDEAL;
+ result->offset_uv = iadc->adc->calib.offset_uv;
+ mutex_unlock(&iadc->adc->adc_lock);
+
+ return 0;
}
-EXPORT_SYMBOL(qpnp_iadc_get_offset);
+EXPORT_SYMBOL(qpnp_iadc_get_gain_and_offset);
static ssize_t qpnp_iadc_show(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- int32_t result;
+ struct qpnp_iadc_result result;
int rc = -1;
rc = qpnp_iadc_read(attr->index, &result);
@@ -478,7 +654,7 @@
return 0;
return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
- "Result:%d\n", result);
+ "Result:%d\n", result.result_ua);
}
static struct sensor_device_attribute qpnp_adc_attr =
@@ -592,10 +768,28 @@
rc = qpnp_iadc_configure_interrupt();
if (rc) {
- dev_err(&spmi->dev, "failed to configure interrupt");
+ dev_err(&spmi->dev, "failed to configure interrupt\n");
return rc;
}
+ rc = qpnp_iadc_version_check();
+ if (rc) {
+ dev_err(&spmi->dev, "IADC version not supported\n");
+ return rc;
+ }
+
+ rc = qpnp_iadc_calibrate_for_trim();
+ if (rc) {
+ dev_err(&spmi->dev, "failed to calibrate for USR trim\n");
+ return rc;
+ }
+ iadc->iadc_init_calib = true;
+ INIT_DELAYED_WORK(&iadc->iadc_work, qpnp_iadc_work);
+ schedule_delayed_work(&iadc->iadc_work,
+ round_jiffies_relative(msecs_to_jiffies
+ (QPNP_IADC_CALIB_SECONDS)));
+ iadc->iadc_initialized = true;
+
return 0;
}
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 13493b8..696c9f9 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -1,5 +1,5 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 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 and
@@ -68,8 +68,6 @@
#define WLED_SYNC_VAL 0x07
#define WLED_SYNC_RESET_VAL 0x00
-#define WLED_TRIGGER_DEFAULT "none"
-#define WLED_FLAGS_DEFAULT 0x00
#define WLED_DEFAULT_STRINGS 0x01
#define WLED_DEFAULT_OVP_VAL 0x02
#define WLED_BOOST_LIM_DEFAULT 0x03
@@ -77,6 +75,8 @@
#define WLED_CTRL_DLY_DEFAULT 0x00
#define WLED_SWITCH_FREQ_DEFAULT 0x02
+#define LED_TRIGGER_DEFAULT "none"
+
/**
* enum qpnp_leds - QPNP supported led ids
* @QPNP_ID_WLED - White led backlight
@@ -119,9 +119,9 @@
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
/* LED1 */
0x60, 0x61, 0x62, 0x63, 0x66,
- /* LED1 */
+ /* LED2 */
0x70, 0x71, 0x72, 0x73, 0x76,
- /* LED1 */
+ /* LED3 */
0x80, 0x81, 0x82, 0x83, 0x86,
};
@@ -155,6 +155,7 @@
* @base_reg - base register given in device tree
* @lock - to protect the transactions
* @reg - cached value of led register
+ * @num_leds - number of leds in the module
* @max_current - maximum current supported by LED
* @default_on - true: default state max, false, default state 0
*/
@@ -164,6 +165,7 @@
int id;
u16 base;
u8 reg;
+ u8 num_leds;
spinlock_t lock;
struct wled_config_data *wled_cfg;
int max_current;
@@ -194,6 +196,22 @@
return rc;
}
+static void qpnp_dump_regs(struct qpnp_led_data *led, u8 regs[], u8 array_size)
+{
+ int i;
+ u8 val;
+
+ pr_debug("===== %s LED register dump start =====\n", led->cdev.name);
+ for (i = 0; i < array_size; i++) {
+ spmi_ext_register_readl(led->spmi_dev->ctrl,
+ led->spmi_dev->sid,
+ led->base + regs[i],
+ &val, sizeof(val));
+ pr_debug("0x%x = 0x%x\n", led->base + regs[i], val);
+ }
+ pr_debug("===== %s LED register dump end =====\n", led->cdev.name);
+}
+
static int qpnp_wled_set(struct qpnp_led_data *led)
{
int rc, duty;
@@ -271,22 +289,6 @@
return 0;
}
-static void qpnp_wled_dump_regs(struct qpnp_led_data *led)
-{
- int i;
- u8 val;
-
- pr_debug("===== WLED register dump start =====\n");
- for (i = 0; i < ARRAY_SIZE(wled_debug_regs); i++) {
- spmi_ext_register_readl(led->spmi_dev->ctrl,
- led->spmi_dev->sid,
- led->base + wled_debug_regs[i],
- &val, sizeof(val));
- pr_debug("0x%x = 0x%x\n", led->base + wled_debug_regs[i], val);
- }
- pr_debug("===== WLED register dump end =====\n");
-}
-
static void qpnp_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
@@ -294,9 +296,8 @@
struct qpnp_led_data *led;
led = container_of(led_cdev, struct qpnp_led_data, cdev);
-
if (value < LED_OFF || value > led->cdev.max_brightness) {
- dev_err(led->cdev.dev, "Invalid brightness value\n");
+ dev_err(&led->spmi_dev->dev, "Invalid brightness value\n");
return;
}
@@ -307,11 +308,11 @@
case QPNP_ID_WLED:
rc = qpnp_wled_set(led);
if (rc < 0)
- dev_err(led->cdev.dev,
+ dev_err(&led->spmi_dev->dev,
"WLED set brightness failed (%d)\n", rc);
break;
default:
- dev_err(led->cdev.dev, "Invalid LED(%d)\n", led->id);
+ dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
break;
}
spin_unlock(&led->lock);
@@ -324,7 +325,7 @@
led->cdev.max_brightness = WLED_MAX_LEVEL;
break;
default:
- dev_err(led->cdev.dev, "Invalid LED(%d)\n", led->id);
+ dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
return -EINVAL;
}
@@ -465,7 +466,7 @@
}
/* dump wled registers */
- qpnp_wled_dump_regs(led);
+ qpnp_dump_regs(led, wled_debug_regs, ARRAY_SIZE(wled_debug_regs));
return 0;
}
@@ -478,17 +479,43 @@
case QPNP_ID_WLED:
rc = qpnp_wled_init(led);
if (rc)
- dev_err(led->cdev.dev,
+ dev_err(&led->spmi_dev->dev,
"WLED initialize failed(%d)\n", rc);
break;
default:
- dev_err(led->cdev.dev, "Invalid LED(%d)\n", led->id);
+ dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
rc = -EINVAL;
}
return rc;
}
+static int __devinit qpnp_get_common_configs(struct qpnp_led_data *led,
+ struct device_node *node)
+{
+ int rc;
+ const char *temp_string;
+
+ led->cdev.default_trigger = LED_TRIGGER_DEFAULT;
+ rc = of_property_read_string(node, "linux,default-trigger",
+ &temp_string);
+ if (!rc)
+ led->cdev.default_trigger = temp_string;
+ else if (rc != -EINVAL)
+ return rc;
+
+ led->default_on = false;
+ rc = of_property_read_string(node, "qcom,default-state",
+ &temp_string);
+ if (!rc) {
+ if (strncmp(temp_string, "on", sizeof("on")) == 0)
+ led->default_on = true;
+ } else if (rc != -EINVAL)
+ return rc;
+
+ return 0;
+}
+
/*
* Handlers for alternative sources of platform_data
*/
@@ -497,9 +524,6 @@
{
u32 val;
int rc;
- const char *temp_string;
-
- led->id = QPNP_ID_WLED;
led->wled_cfg = devm_kzalloc(&led->spmi_dev->dev,
sizeof(struct wled_config_data), GFP_KERNEL);
@@ -508,31 +532,6 @@
return -ENOMEM;
}
- led->cdev.default_trigger = WLED_TRIGGER_DEFAULT;
- rc = of_property_read_string(node, "linux,default-trigger",
- &temp_string);
- if (!rc)
- led->cdev.default_trigger = temp_string;
- else if (rc != -EINVAL)
- return rc;
-
-
- led->cdev.flags = WLED_FLAGS_DEFAULT;
- rc = of_property_read_u32(node, "qcom,flags", &val);
- if (!rc)
- led->cdev.flags = (int) val;
- else if (rc != -EINVAL)
- return rc;
-
- led->default_on = true;
- rc = of_property_read_string(node, "qcom,default-state",
- &temp_string);
- if (!rc) {
- if (!strncmp(temp_string, "off", sizeof("off")))
- led->default_on = false;
- } else if (rc != -EINVAL)
- return rc;
-
led->wled_cfg->num_strings = WLED_DEFAULT_STRINGS;
rc = of_property_read_u32(node, "qcom,num-strings", &val);
if (!rc)
@@ -591,105 +590,135 @@
{
struct qpnp_led_data *led;
struct resource *led_resource;
- struct device_node *node;
- int rc;
+ struct device_node *node, *temp;
+ int rc, i, num_leds = 0;
const char *led_label;
- led = devm_kzalloc(&spmi->dev, (sizeof(struct qpnp_led_data)),
- GFP_KERNEL);
+ node = spmi->dev.of_node;
+ if (node == NULL)
+ return -ENODEV;
+
+ temp = NULL;
+ while ((temp = of_get_next_child(node, temp)))
+ num_leds++;
+
+ led = devm_kzalloc(&spmi->dev,
+ (sizeof(struct qpnp_led_data) * num_leds), GFP_KERNEL);
if (!led) {
dev_err(&spmi->dev, "Unable to allocate memory\n");
return -ENOMEM;
}
- led->spmi_dev = spmi;
+ led->num_leds = num_leds;
+ num_leds = 0;
- led_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
- if (!led_resource) {
- dev_err(&spmi->dev, "Unable to get LED base address\n");
- return -ENXIO;
- }
- led->base = led_resource->start;
+ for_each_child_of_node(node, temp) {
+ led->spmi_dev = spmi;
- dev_set_drvdata(&spmi->dev, led);
+ led_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
+ if (!led_resource) {
+ dev_err(&spmi->dev, "Unable to get LED base address\n");
+ return -ENXIO;
+ }
+ led->base = led_resource->start;
- node = led->spmi_dev->dev.of_node;
- if (node == NULL)
- return -ENODEV;
+ dev_set_drvdata(&spmi->dev, led);
- rc = of_property_read_string(node, "qcom,label", &led_label);
- if (rc < 0) {
- dev_err(&led->spmi_dev->dev,
- "Failure reading label, rc = %d\n", rc);
- return rc;
- }
- rc = of_property_read_string(node, "qcom,name", &led->cdev.name);
- if (rc < 0) {
- dev_err(&led->spmi_dev->dev,
- "Failure reading led name, rc = %d\n", rc);
- return rc;
- }
-
- rc = of_property_read_u32(node, "qcom,max-current", &led->max_current);
- if (rc < 0) {
- dev_err(&led->spmi_dev->dev,
- "Failure reading max_current, rc = %d\n", rc);
- return rc;
- }
-
- led->cdev.brightness_set = qpnp_led_set;
- led->cdev.brightness_get = qpnp_led_get;
- led->cdev.brightness = LED_OFF;
-
- if (strncmp(led_label, "wled", sizeof("wled")) == 0) {
- rc = qpnp_get_config_wled(led, node);
+ rc = of_property_read_string(temp, "label", &led_label);
if (rc < 0) {
dev_err(&led->spmi_dev->dev,
- "Unable to read wled config data\n");
+ "Failure reading label, rc = %d\n", rc);
return rc;
}
- } else {
- dev_err(&led->spmi_dev->dev, "No LED matching label\n");
- return -EINVAL;
+
+ rc = of_property_read_string(temp, "linux,name",
+ &led->cdev.name);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev,
+ "Failure reading led name, rc = %d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32(temp, "qcom,max-current",
+ &led->max_current);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev,
+ "Failure reading max_current, rc = %d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32(temp, "qcom,id", &led->id);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev,
+ "Failure reading led id, rc = %d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_get_common_configs(led, temp);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Failure reading common led configuration," \
+ " rc = %d\n", rc);
+ return rc;
+ }
+
+ led->cdev.brightness_set = qpnp_led_set;
+ led->cdev.brightness_get = qpnp_led_get;
+
+ if (strncmp(led_label, "wled", sizeof("wled")) == 0) {
+ rc = qpnp_get_config_wled(led, temp);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev,
+ "Unable to read wled config data\n");
+ return rc;
+ }
+ } else {
+ dev_err(&led->spmi_dev->dev, "No LED matching label\n");
+ return -EINVAL;
+ }
+
+ spin_lock_init(&led->lock);
+
+ rc = qpnp_led_initialize(led);
+ if (rc < 0)
+ goto fail_id_check;
+
+ rc = qpnp_led_set_max_brightness(led);
+ if (rc < 0)
+ goto fail_id_check;
+
+ rc = led_classdev_register(&spmi->dev, &led->cdev);
+ if (rc) {
+ dev_err(&spmi->dev, "unable to register led %d,rc=%d\n",
+ led->id, rc);
+ goto fail_id_check;
+ }
+ /* configure default state */
+ if (led->default_on)
+ led->cdev.brightness = led->cdev.max_brightness;
+ else
+ led->cdev.brightness = LED_OFF;
+
+ qpnp_led_set(&led->cdev, led->cdev.brightness);
+ led++;
+ num_leds++;
}
-
- spin_lock_init(&led->lock);
-
- rc = qpnp_led_initialize(led);
- if (rc < 0)
- goto fail_id_check;
-
- rc = qpnp_led_set_max_brightness(led);
- if (rc < 0)
- goto fail_id_check;
-
-
- rc = led_classdev_register(&spmi->dev, &led->cdev);
- if (rc) {
- dev_err(&spmi->dev, "unable to register led %d,rc=%d\n",
- led->id, rc);
- goto fail_id_check;
- }
-
- /* configure default state */
- if (led->default_on)
- led->cdev.brightness = led->cdev.max_brightness;
-
- qpnp_led_set(&led->cdev, led->cdev.brightness);
-
return 0;
fail_id_check:
- led_classdev_unregister(&led->cdev);
+ for (i = 0; i < num_leds; i++)
+ led_classdev_unregister(&led[i].cdev);
return rc;
}
static int __devexit qpnp_leds_remove(struct spmi_device *spmi)
{
struct qpnp_led_data *led = dev_get_drvdata(&spmi->dev);
+ int i;
- led_classdev_unregister(&led->cdev);
+ for (i = 0; i < led->num_leds; i++)
+ led_classdev_unregister(&led[i].cdev);
return 0;
}
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index d9f62ad..cbd3b38 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -98,6 +98,18 @@
return index;
}
+static inline int dvb_dmxdev_events_is_full(struct dmxdev_events_queue *events)
+{
+ int new_write_index;
+
+ new_write_index = dvb_dmxdev_advance_event_idx(events->write_index);
+ if (new_write_index == events->read_index)
+ return 1;
+
+ return 0;
+
+}
+
static inline void dvb_dmxdev_flush_events(struct dmxdev_events_queue *events)
{
events->read_index = 0;
@@ -788,6 +800,13 @@
spin_lock_irq(&dmxdev->lock);
dvb_dmxdev_update_events(&dmxdev->dvr_output_events, res);
spin_unlock_irq(&dmxdev->lock);
+
+ /*
+ * in PULL mode, we might be stalling on
+ * event queue, so need to wake-up waiters
+ */
+ if (dmxdev->playback_mode == DMX_PB_MODE_PULL)
+ wake_up_all(&dmxdev->dvr_buffer.queue);
} else if (res == -EOVERFLOW) {
/*
* When buffer overflowed, demux-dev flushed the
@@ -1037,6 +1056,13 @@
spin_unlock_irq(&dmxdev->lock);
+ /*
+ * in PULL mode, we might be stalling on
+ * event queue, so need to wake-up waiters
+ */
+ if (dmxdev->playback_mode == DMX_PB_MODE_PULL)
+ wake_up_all(&dmxdev->dvr_buffer.queue);
+
return res;
}
@@ -1303,13 +1329,17 @@
{
struct dmxdev_filter *dmxdevfilter = filter->priv;
struct dvb_ringbuffer *src;
+ struct dmxdev_events_queue *events;
int ret;
if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
- || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
+ || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) {
src = &dmxdevfilter->buffer;
- else
+ events = &dmxdevfilter->events;
+ } else {
src = &dmxdevfilter->dev->dvr_buffer;
+ events = &dmxdevfilter->dev->dvr_output_events;
+ }
do {
ret = 0;
@@ -1330,7 +1360,8 @@
return ret;
}
- if (required_space <= dvb_ringbuffer_free(src)) {
+ if ((required_space <= dvb_ringbuffer_free(src)) &&
+ (!dvb_dmxdev_events_is_full(events))) {
spin_unlock(&dmxdevfilter->dev->lock);
return 0;
}
@@ -1339,7 +1370,8 @@
ret = wait_event_interruptible(src->queue,
(!src->data) ||
- (dvb_ringbuffer_free(src) >= required_space) ||
+ ((dvb_ringbuffer_free(src) >= required_space) &&
+ (!dvb_dmxdev_events_is_full(events))) ||
(src->error != 0) ||
(dmxdevfilter->state != DMXDEV_STATE_GO) ||
dmxdevfilter->dev->dvr_in_exit);
@@ -1355,6 +1387,7 @@
{
struct dmxdev_filter *dmxdevfilter = filter->priv;
struct dvb_ringbuffer *src = &dmxdevfilter->buffer;
+ struct dmxdev_events_queue *events = &dmxdevfilter->events;
int ret;
do {
@@ -1376,7 +1409,8 @@
return ret;
}
- if (required_space <= dvb_ringbuffer_free(src)) {
+ if ((required_space <= dvb_ringbuffer_free(src)) &&
+ (!dvb_dmxdev_events_is_full(events))) {
spin_unlock(&dmxdevfilter->dev->lock);
return 0;
}
@@ -1385,7 +1419,8 @@
ret = wait_event_interruptible(src->queue,
(!src->data) ||
- (dvb_ringbuffer_free(src) >= required_space) ||
+ ((dvb_ringbuffer_free(src) >= required_space) &&
+ (!dvb_dmxdev_events_is_full(events))) ||
(src->error != 0) ||
(dmxdevfilter->state != DMXDEV_STATE_GO) ||
dmxdevfilter->dev->dvr_in_exit);
@@ -1537,6 +1572,13 @@
spin_unlock_irq(&dmxdevfilter->dev->lock);
+ /*
+ * in PULL mode, we might be stalling on
+ * event queue, so need to wake-up waiters
+ */
+ if (dmxdevfilter->dev->playback_mode == DMX_PB_MODE_PULL)
+ wake_up_all(&dmxdevfilter->buffer.queue);
+
return res;
}
@@ -2608,6 +2650,13 @@
spin_lock_irq(&dmxdevfilter->dev->lock);
dvb_dmxdev_update_events(&dmxdevfilter->events, ret);
spin_unlock_irq(&dmxdevfilter->dev->lock);
+
+ /*
+ * in PULL mode, we might be stalling on
+ * event queue, so need to wake-up waiters
+ */
+ if (dmxdevfilter->dev->playback_mode == DMX_PB_MODE_PULL)
+ wake_up_all(&dmxdevfilter->buffer.queue);
} else if (ret == -EOVERFLOW) {
/*
* When buffer overflowed, demux-dev flushed the
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
index 627c5a2..2e783f6 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
@@ -30,15 +30,16 @@
#define DMX_TSIF_CHUNKS_IN_BUF 16
#define DMX_TSIF_TIME_LIMIT 10000
-/* TSIF_DRIVER_MODE: 3 means manual control from debugfs. use 1 normally. */
-#define DMX_TSIF_DRIVER_MODE_DEF 1
-
+/* TSIF_DRIVER_MODE: 3 means manual control from debugfs. use 2 normally. */
+#define DMX_TSIF_DRIVER_MODE_DEF 2
/* module parameters for load time configuration: */
static int threshold = DMX_TSIF_PACKETS_IN_CHUNK_DEF;
-static int mode = DMX_TSIF_DRIVER_MODE_DEF;
+static int tsif_mode = DMX_TSIF_DRIVER_MODE_DEF;
+static int clock_inv;
module_param(threshold, int, S_IRUGO);
-module_param(mode, int, S_IRUGO);
+module_param(tsif_mode, int, S_IRUGO);
+module_param(clock_inv, int, S_IRUGO);
/*
* Work scheduled each time TSIF notifies dmx
@@ -273,7 +274,6 @@
tsif_driver = &(mpq_dmx_tsif_info.tsif[tsif].tsif_driver);
/* Attach to TSIF driver */
-
tsif_driver->tsif_handler =
tsif_attach(tsif, mpq_tsif_callback, (void *)tsif);
if (IS_ERR_OR_NULL(tsif_driver->tsif_handler)) {
@@ -284,12 +284,19 @@
return -ENODEV;
}
+ ret = tsif_set_clk_inverse(tsif_driver->tsif_handler,
+ clock_inv);
+ if (ret < 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: tsif_set_clk_inverse (%d) failed\n",
+ __func__, clock_inv);
+ }
+
/* Set TSIF driver mode */
- ret = tsif_set_mode(tsif_driver->tsif_handler,
- mode);
+ ret = tsif_set_mode(tsif_driver->tsif_handler, tsif_mode);
if (ret < 0) {
MPQ_DVB_ERR_PRINT("%s: tsif_set_mode (%d) failed\n",
- __func__, mode);
+ __func__, tsif_mode);
}
/* Set TSIF buffer configuration */
@@ -304,18 +311,6 @@
MPQ_DVB_ERR_PRINT("Using default TSIF driver values\n");
}
-
- /* Set TSIF driver time limit */
- /* TODO: needed?? */
-/* ret = tsif_set_time_limit(tsif_driver->tsif_handler,
- DMX_TSIF_TIME_LIMIT);
- if (ret < 0) {
- MPQ_DVB_ERR_PRINT(
- "%s: tsif_set_time_limit (%d) failed\n",
- __func__, DMX_TSIF_TIME_LIMIT);
- }
-*/
-
/* Start TSIF driver */
ret = tsif_start(tsif_driver->tsif_handler);
if (ret < 0) {
@@ -705,11 +700,11 @@
__func__, DMX_TSIF_PACKETS_IN_CHUNK_DEF);
threshold = DMX_TSIF_PACKETS_IN_CHUNK_DEF;
}
- if ((mode < 1) || (mode > 3)) {
+ if ((tsif_mode < 1) || (tsif_mode > 3)) {
MPQ_DVB_ERR_PRINT(
"%s: invalid mode parameter, using %d instead\n",
__func__, DMX_TSIF_DRIVER_MODE_DEF);
- mode = DMX_TSIF_DRIVER_MODE_DEF;
+ tsif_mode = DMX_TSIF_DRIVER_MODE_DEF;
}
for (i = 0; i < TSIF_COUNT; i++) {
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
index 68af7e1..191a0c4 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
@@ -66,10 +66,10 @@
#define TSPP_CHANNEL_TIMEOUT 16
/* module parameters for load time configuration */
-static int tsif0_mode = TSPP_TSIF_MODE_2;
-static int tsif1_mode = TSPP_TSIF_MODE_2;
-module_param(tsif0_mode, int, S_IRUGO);
-module_param(tsif1_mode, int, S_IRUGO);
+static int clock_inv;
+static int tsif_mode = 2;
+module_param(tsif_mode, int, S_IRUGO);
+module_param(clock_inv, int, S_IRUGO);
/*
* Work scheduled each time TSPP notifies dmx
@@ -279,20 +279,30 @@
int channel_id;
int *channel_ref_count;
- tspp_source.clk_inverse = 0;
+ tspp_source.clk_inverse = clock_inv;
tspp_source.data_inverse = 0;
tspp_source.sync_inverse = 0;
tspp_source.enable_inverse = 0;
+ switch (tsif_mode) {
+ case 1:
+ tspp_source.mode = TSPP_TSIF_MODE_1;
+ break;
+ case 2:
+ tspp_source.mode = TSPP_TSIF_MODE_2;
+ break;
+ default:
+ tspp_source.mode = TSPP_TSIF_MODE_LOOPBACK;
+ break;
+ }
+
/* determine the TSIF we are reading from */
if (mpq_demux->source == DMX_SOURCE_FRONT0) {
tsif = 0;
tspp_source.source = TSPP_SOURCE_TSIF0;
- tspp_source.mode = (enum tspp_tsif_mode)tsif0_mode;
} else if (mpq_demux->source == DMX_SOURCE_FRONT1) {
tsif = 1;
tspp_source.source = TSPP_SOURCE_TSIF1;
- tspp_source.mode = (enum tspp_tsif_mode)tsif1_mode;
} else {
/* invalid source */
MPQ_DVB_ERR_PRINT(
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index 7d44fea..eb0cd8a 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -671,7 +671,6 @@
if (rc)
dprintk(VIDC_WARN,
"Failed in %s for release output buffers\n", __func__);
- rc = msm_vidc_close(vidc_inst);
list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
bi = list_entry(ptr, struct buffer_info, list);
if (bi->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
@@ -686,6 +685,7 @@
}
}
msm_smem_delete_client(v4l2_inst->mem_client);
+ rc = msm_vidc_close(vidc_inst);
kfree(v4l2_inst);
return rc;
}
@@ -958,17 +958,35 @@
rc = msm_v4l2_release_output_buffers(v4l2_inst);
if (rc)
dprintk(VIDC_WARN,
- "Failed in %s for release output buffers\n", __func__);
+ "Failed to release dec output buffers: %d\n", rc);
return msm_vidc_decoder_cmd((void *)vidc_inst, dec);
}
static int msm_v4l2_encoder_cmd(struct file *file, void *fh,
struct v4l2_encoder_cmd *enc)
{
+ struct msm_v4l2_vid_inst *v4l2_inst;
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ int rc = 0;
+ v4l2_inst = get_v4l2_inst(file, NULL);
+ if (enc->cmd == V4L2_ENC_CMD_STOP)
+ rc = msm_v4l2_release_output_buffers(v4l2_inst);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed to release enc output buffers: %d\n", rc);
return msm_vidc_encoder_cmd((void *)vidc_inst, enc);
}
-
+static int msm_v4l2_s_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_s_parm((void *)vidc_inst, a);
+}
+static int msm_v4l2_g_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a)
+{
+ return 0;
+}
static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
.vidioc_querycap = msm_v4l2_querycap,
.vidioc_enum_fmt_vid_cap_mplane = msm_v4l2_enum_fmt,
@@ -989,6 +1007,8 @@
.vidioc_unsubscribe_event = msm_v4l2_unsubscribe_event,
.vidioc_decoder_cmd = msm_v4l2_decoder_cmd,
.vidioc_encoder_cmd = msm_v4l2_encoder_cmd,
+ .vidioc_s_parm = msm_v4l2_s_parm,
+ .vidioc_g_parm = msm_v4l2_g_parm
};
static const struct v4l2_ioctl_ops msm_v4l2_enc_ioctl_ops = {
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index 058c835..3afc496 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -544,7 +544,42 @@
}
return rc;
}
-
+int msm_vdec_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a)
+{
+ u32 us_per_frame = 0;
+ int rc = 0;
+ if (a->parm.output.timeperframe.denominator) {
+ switch (a->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ us_per_frame = a->parm.output.timeperframe.numerator/
+ a->parm.output.timeperframe.denominator;
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ us_per_frame = a->parm.capture.timeperframe.numerator/
+ a->parm.capture.timeperframe.denominator;
+ break;
+ default:
+ dprintk(VIDC_ERR,
+ "Scale clocks : Unknown buffer type\n");
+ break;
+ }
+ }
+ if (!us_per_frame) {
+ dprintk(VIDC_ERR,
+ "Failed to scale clocks : time between frames is 0\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+ inst->prop.fps = (u8) (USEC_PER_SEC / us_per_frame);
+ if (inst->prop.fps) {
+ if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
+ dprintk(VIDC_WARN,
+ "Failed to scale clocks\n");
+ }
+ }
+exit:
+ return rc;
+}
int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
{
const struct msm_vidc_format *fmt = NULL;
diff --git a/drivers/media/video/msm_vidc/msm_vdec.h b/drivers/media/video/msm_vidc/msm_vdec.h
index b8326d8..419c8c1 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.h
+++ b/drivers/media/video/msm_vidc/msm_vdec.h
@@ -32,6 +32,7 @@
int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
int msm_vdec_cmd(struct msm_vidc_inst *inst, struct v4l2_decoder_cmd *dec);
+int msm_vdec_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a);
struct vb2_ops *msm_vdec_get_vb2q_ops(void);
#endif
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 0ea2a60..3f892b1 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -1274,6 +1274,14 @@
v4l2_event_queue_fh(&inst->event_handler, &dqevent);
return rc;
}
+ rc = msm_comm_release_scratch_buffers(inst);
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to release scratch buf:%d\n",
+ rc);
+ rc = msm_comm_release_persist_buffers(inst);
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to release persist buf:%d\n",
+ rc);
rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
break;
}
@@ -1331,6 +1339,55 @@
return rc;
}
+int msm_venc_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a)
+{
+ u32 property_id = 0, us_per_frame = 0;
+ void *pdata;
+ int rc = 0;
+ struct hal_frame_rate frame_rate;
+ property_id = HAL_CONFIG_FRAME_RATE;
+ if (a->parm.output.timeperframe.denominator) {
+ switch (a->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ us_per_frame = a->parm.output.timeperframe.numerator/
+ a->parm.output.timeperframe.denominator;
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ us_per_frame = a->parm.capture.timeperframe.numerator/
+ a->parm.capture.timeperframe.denominator;
+ break;
+ default:
+ dprintk(VIDC_ERR,
+ "Scale clocks : Unknown buffer type\n");
+ break;
+ }
+ }
+
+ if (!us_per_frame) {
+ dprintk(VIDC_ERR,
+ "Failed to scale clocks : time between frames is 0\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+ inst->prop.fps = (u8) (USEC_PER_SEC / us_per_frame);
+ if (inst->prop.fps) {
+ frame_rate.frame_rate = inst->prop.fps * (0x1<<16);
+ frame_rate.buffer_type = HAL_BUFFER_OUTPUT;
+ pdata = &frame_rate;
+ rc = vidc_hal_session_set_property((void *)inst->session,
+ property_id, pdata);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed to set frame rate %d\n", rc);
+ }
+ if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
+ dprintk(VIDC_WARN,
+ "Failed to scale clocks\n");
+ }
+ }
+exit:
+ return rc;
+}
int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
{
const struct msm_vidc_format *fmt = NULL;
@@ -1507,6 +1564,43 @@
return rc;
}
+int msm_venc_release_buf(struct msm_vidc_inst *inst,
+ struct v4l2_buffer *b)
+{
+ int rc = 0;
+ int i;
+ struct vidc_buffer_addr_info buffer_info;
+
+ switch (b->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ for (i = 0; i < b->length; i++) {
+ dprintk(VIDC_DBG,
+ "Release device_addr = %ld, size = %d, %d\n",
+ b->m.planes[i].m.userptr,
+ b->m.planes[i].length, inst->state);
+ buffer_info.buffer_size = b->m.planes[i].length;
+ buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr =
+ b->m.planes[i].m.userptr;
+ buffer_info.extradata_size = 0;
+ buffer_info.extradata_addr = 0;
+ rc = vidc_hal_session_release_buffers(
+ (void *)inst->session, &buffer_info);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "vidc_hal_session_release_buffers failed\n");
+ }
+ break;
+ default:
+ dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
+ break;
+ }
+ return rc;
+}
+
int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
{
struct buf_queue *q = NULL;
diff --git a/drivers/media/video/msm_vidc/msm_venc.h b/drivers/media/video/msm_vidc/msm_venc.h
index 83610b3..ad63e7d 100644
--- a/drivers/media/video/msm_vidc/msm_venc.h
+++ b/drivers/media/video/msm_vidc/msm_venc.h
@@ -26,11 +26,13 @@
int msm_venc_g_ctrl(void *instance, struct v4l2_control *a);
int msm_venc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
int msm_venc_prepare_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_release_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
int msm_venc_cmd(struct msm_vidc_inst *inst, struct v4l2_encoder_cmd *enc);
+int msm_venc_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a);
struct vb2_ops *msm_venc_get_vb2q_ops(void);
#endif
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index 7ceb017..1d0124f 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -109,6 +109,19 @@
return msm_venc_querycap(instance, cap);
return -EINVAL;
}
+int msm_vidc_s_parm(void *instance,
+ struct v4l2_streamparm *a)
+{
+ struct msm_vidc_inst *inst = instance;
+
+ if (!inst || !a)
+ return -EINVAL;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_s_parm(instance, a);
+ else if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_s_parm(instance, a);
+ return -EINVAL;
+}
int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f)
{
struct msm_vidc_inst *inst = instance;
@@ -211,6 +224,8 @@
if (inst->session_type == MSM_VIDC_DECODER)
return msm_vdec_release_buf(instance, b);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_release_buf(instance, b);
return -EINVAL;
}
@@ -540,13 +555,13 @@
list_del(&inst->list);
}
mutex_unlock(&core->sync_lock);
+ cleanup_instance(inst);
if (inst->state != MSM_VIDC_CORE_INVALID &&
core->state != VIDC_CORE_INVALID)
rc = msm_comm_try_state(inst, MSM_VIDC_CORE_UNINIT);
if (rc)
dprintk(VIDC_ERR,
"Failed to move video instance to uninit state\n");
- cleanup_instance(inst);
pr_info(VIDC_DBG_TAG "Closed video instance: %p\n", VIDC_INFO, inst);
kfree(inst);
return 0;
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index 54c3d5f..038f03e 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -528,6 +528,7 @@
dqevent.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
dqevent.id = 0;
v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+ inst->session = NULL;
wake_up(&inst->kernel_event_queue);
show_stats(inst);
} else {
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 53e965c..7d1fdf0 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -219,6 +219,7 @@
dev_err(wcd9xxx->dev, "Failed to read interrupt status: %d\n",
ret);
dev_err(wcd9xxx->dev, "Disable irq %d\n", wcd9xxx->irq);
+ disable_irq_wake(wcd9xxx->irq);
disable_irq_nosync(wcd9xxx->irq);
wcd9xxx_unlock_sleep(wcd9xxx);
return IRQ_NONE;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 3aa38d2..48516b6 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2639,7 +2639,9 @@
mmc_card_is_removable(host))
return err;
- mmc_claim_host(host);
+ if (!mmc_try_claim_host(host))
+ return -EBUSY;
+
if (card && mmc_card_mmc(card) &&
(card->ext_csd.cache_size > 0)) {
enable = !!enable;
diff --git a/drivers/net/ethernet/msm/msm_rmnet_smux.c b/drivers/net/ethernet/msm/msm_rmnet_smux.c
index 5f29406..e56a64e 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_smux.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_smux.c
@@ -482,7 +482,7 @@
p = netdev_priv(priv);
DBG0("[%s] Low WM hit dev:%s\n", __func__, dev->name);
spin_lock_irqsave(&p->tx_queue_lock, flags);
- netif_start_queue(dev);
+ netif_wake_queue(dev);
spin_unlock_irqrestore(&p->tx_queue_lock, flags);
break;
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index d2d0c03..cf34df5 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-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 and
@@ -986,30 +986,6 @@
PM8921_CHG_LED_SRC_CONFIG_MASK, temp);
}
-static void disable_input_voltage_regulation(struct pm8921_chg_chip *chip)
-{
- u8 temp;
- int rc;
-
- rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x70);
- if (rc) {
- pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
- return;
- }
- rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
- if (rc) {
- pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
- return;
- }
- /* set the input voltage disable bit and the write bit */
- temp |= 0x81;
- rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
- if (rc) {
- pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
- return;
- }
-}
-
static void enable_input_voltage_regulation(struct pm8921_chg_chip *chip)
{
u8 temp;
@@ -2594,29 +2570,49 @@
return IRQ_HANDLED;
}
-static int param_vin_disable_counter = 5;
-module_param(param_vin_disable_counter, int, 0644);
+enum {
+ PON_TIME_25NS = 0x04,
+ PON_TIME_50NS = 0x08,
+ PON_TIME_100NS = 0x0C,
+};
-static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip,
- int count, int usb_ma)
+static void set_min_pon_time(struct pm8921_chg_chip *chip, int pon_time_ns)
{
- if (usb_ma)
- __pm8921_charger_vbus_draw(500);
- pr_debug("count = %d iusb=500mA\n", count);
- disable_input_voltage_regulation(chip);
- pr_debug("count = %d disable_input_regulation\n", count);
+ u8 temp;
+ int rc;
- msleep(20);
+ rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x40);
+ if (rc) {
+ pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
+ return;
+ }
+ rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
+ if (rc) {
+ pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
+ return;
+ }
+ /* clear the min pon time select bit */
+ temp &= 0xF3;
+ /* set the pon time */
+ temp |= (u8)pon_time_ns;
+ /* write enable bank 4 */
+ temp |= 0x80;
+ rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
+ if (rc) {
+ pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
+ return;
+ }
+}
- pr_debug("count = %d end sleep 20ms chg_gone=%d, usb_valid = %d\n",
- count,
- pm_chg_get_rt_status(chip, CHG_GONE_IRQ),
- is_usb_chg_plugged_in(chip));
- pr_debug("count = %d restoring input regulation and usb_ma = %d\n",
- count, usb_ma);
- enable_input_voltage_regulation(chip);
- if (usb_ma)
- __pm8921_charger_vbus_draw(usb_ma);
+static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip)
+{
+ pr_debug("Start\n");
+ set_min_pon_time(chip, PON_TIME_100NS);
+ pm_chg_vinmin_set(chip, chip->vin_min + 200);
+ msleep(250);
+ pm_chg_vinmin_set(chip, chip->vin_min);
+ set_min_pon_time(chip, PON_TIME_25NS);
+ pr_debug("End\n");
}
#define VIN_ACTIVE_BIT BIT(0)
@@ -2647,11 +2643,6 @@
pr_debug("USB charger active\n");
pm_chg_iusbmax_get(chip, &usb_ma);
- if (usb_ma == 500 && !usb_target_ma) {
- pr_debug("Stopping Unplug Check Worker USB == 500mA\n");
- disable_input_voltage_regulation(chip);
- return;
- }
if (usb_ma <= 100) {
pr_debug(
@@ -2661,8 +2652,10 @@
}
} else if (active_path & DC_ACTIVE_BIT) {
pr_debug("DC charger active\n");
- /* Some board designs are not prone to reverse boost on DC
- * charging path */
+ /*
+ * Some board designs are not prone to reverse boost on DC
+ * charging path
+ */
if (!chip->dc_unplug_check)
return;
} else {
@@ -2701,27 +2694,17 @@
ibat = get_prop_batt_current(chip);
if (reg_loop & VIN_ACTIVE_BIT) {
- pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
- ibat, pm_chg_get_fsm_state(chip), reg_loop);
if (ibat > 0) {
- int count = 0;
-
- while (count++ < param_vin_disable_counter
- && active_chg_plugged_in == 1) {
- if (active_path & USB_ACTIVE_BIT)
- attempt_reverse_boost_fix(chip,
- count, usb_ma);
- else
- attempt_reverse_boost_fix(chip,
- count, 0);
- /* after reverse boost fix check if the active
- * charger was detected as removed */
- active_chg_plugged_in
- = is_active_chg_plugged_in(chip,
- active_path);
- pr_debug("active_chg_plugged_in = %d\n",
- active_chg_plugged_in);
- }
+ pr_debug("revboost ibat = %d fsm = %d loop = 0x%x\n",
+ ibat, pm_chg_get_fsm_state(chip), reg_loop);
+ attempt_reverse_boost_fix(chip);
+ /* after reverse boost fix check if the active
+ * charger was detected as removed */
+ active_chg_plugged_in
+ = is_active_chg_plugged_in(chip,
+ active_path);
+ pr_debug("revboost post: active_chg_plugged_in = %d\n",
+ active_chg_plugged_in);
}
}
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index ef555f7..bc012ca 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -189,6 +189,7 @@
bool chg_done;
bool usb_present;
bool dc_present;
+ bool charging_disabled;
unsigned int max_bat_chg_current;
unsigned int safe_voltage_mv;
unsigned int max_voltage_mv;
@@ -202,9 +203,6 @@
uint32_t flags;
};
-static struct qpnp_chg_chip *the_chip;
-static bool charging_disabled;
-
static struct of_device_id qpnp_charger_match_table[] = {
{ .compatible = QPNP_CHARGER_DEV_NAME, },
{}
@@ -424,6 +422,20 @@
return IRQ_HANDLED;
}
+static int
+qpnp_batt_property_is_writeable(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CHARGING_ENABLED:
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static enum power_supply_property pm_power_props_mains[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_ONLINE,
@@ -462,7 +474,7 @@
case POWER_SUPPLY_PROP_PRESENT:
case POWER_SUPPLY_PROP_ONLINE:
val->intval = 0;
- if (charging_disabled)
+ if (chip->charging_disabled)
return 0;
val->intval = qpnp_chg_is_dc_chg_plugged_in(chip);
@@ -753,7 +765,7 @@
val->intval = get_prop_full_design(chip);
break;
case POWER_SUPPLY_PROP_CHARGING_ENABLED:
- val->intval = !charging_disabled;
+ val->intval = !(chip->charging_disabled);
break;
default:
return -EINVAL;
@@ -776,7 +788,7 @@
qpnp_chg_charge_en(chip, val->intval);
else
qpnp_chg_charge_dis(chip, val->intval);
- charging_disabled = !(val->intval);
+ chip->charging_disabled = !(val->intval);
break;
default:
return -EINVAL;
@@ -786,25 +798,6 @@
return 0;
}
-static int
-qpnp_chg_set_disable_status_param(const char *val, struct kernel_param *kp)
-{
- int ret;
- struct qpnp_chg_chip *chip = the_chip;
-
- ret = param_set_int(val, kp);
- if (ret) {
- pr_err("error setting value %d\n", ret);
- return ret;
- }
- pr_info("factory set disable param to %d\n", charging_disabled);
- if (chip)
- qpnp_chg_charge_dis(chip, charging_disabled);
- return 0;
-}
-module_param_call(disabled, qpnp_chg_set_disable_status_param, param_get_bool,
- &charging_disabled, 0644);
-
#define QPNP_CHG_VINMIN_MIN_MV 3400
#define QPNP_CHG_VINMIN_HIGH_MIN_MV 5600
#define QPNP_CHG_VINMIN_HIGH_MIN_VAL 0x2B
@@ -1146,7 +1139,7 @@
}
/* Get the charging-disabled property */
- charging_disabled = of_property_read_bool(spmi->dev.of_node,
+ chip->charging_disabled = of_property_read_bool(spmi->dev.of_node,
"qcom,chg-charging-disabled");
spmi_for_each_container_dev(spmi_resource, spmi) {
@@ -1259,6 +1252,7 @@
chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props);
chip->batt_psy.get_property = qpnp_batt_power_get_property;
chip->batt_psy.set_property = qpnp_batt_power_set_property;
+ chip->batt_psy.property_is_writeable = qpnp_batt_property_is_writeable;
chip->batt_psy.external_power_changed =
qpnp_batt_external_power_changed;
@@ -1280,9 +1274,8 @@
power_supply_set_present(chip->usb_psy,
qpnp_chg_is_usb_chg_plugged_in(chip));
- qpnp_chg_charge_en(chip, 1);
- the_chip = chip;
- qpnp_chg_charge_dis(chip, charging_disabled);
+ qpnp_chg_charge_en(chip, !chip->charging_disabled);
+ qpnp_chg_charge_dis(chip, chip->charging_disabled);
pr_info("Probe success !\n");
return 0;
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 0fd9ab5..0531f83 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -33,6 +33,7 @@
#include <linux/usb/gadget.h>
#include <linux/usb/msm_hsusb.h>
#include <linux/regulator/consumer.h>
+#include <linux/power_supply.h>
#include <mach/rpm-regulator.h>
#include <mach/msm_xo.h>
@@ -157,6 +158,11 @@
u8 dcd_retries;
u32 bus_perf_client;
struct msm_bus_scale_pdata *bus_scale_table;
+ struct power_supply usb_psy;
+ unsigned int online;
+ unsigned int host_mode;
+ unsigned int current_max;
+ bool vbus_active;
};
#define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */
@@ -1281,6 +1287,10 @@
dev_err(mdwc->dev, "Failed to reset bus bw vote\n");
}
+ if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability)
+ dwc3_hsusb_ldo_enable(0);
+
+ dwc3_hsusb_config_vddcx(0);
wake_unlock(&mdwc->wlock);
atomic_set(&mdwc->in_lpm, 1);
@@ -1315,6 +1325,10 @@
dev_err(mdwc->dev, "%s failed to vote for TCXO buffer%d\n",
__func__, ret);
+ if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability)
+ dwc3_hsusb_ldo_enable(1);
+
+ dwc3_hsusb_config_vddcx(1);
clk_prepare_enable(mdwc->ref_clk);
usleep_range(1000, 1200);
@@ -1373,10 +1387,13 @@
mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
DWC3_EVENT_PHY_RESUME);
pm_runtime_put_sync(mdwc->dev);
+ if (mdwc->otg_xceiv && (mdwc->ext_xceiv.otg_capability))
+ mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
+ DWC3_EVENT_XCEIV_STATE);
}
}
-static bool debug_id, debug_bsv, debug_connect;
+static u32 debug_id, debug_bsv, debug_connect;
static int dwc3_connect_show(struct seq_file *s, void *unused)
{
@@ -1446,11 +1463,11 @@
return;
if (!debugfs_create_bool("id", S_IRUGO | S_IWUSR, dwc3_debugfs_root,
- (u32 *)&debug_id))
+ &debug_id))
goto error;
if (!debugfs_create_bool("bsv", S_IRUGO | S_IWUSR, dwc3_debugfs_root,
- (u32 *)&debug_bsv))
+ &debug_bsv))
goto error;
if (!debugfs_create_file("connect", S_IRUGO | S_IWUSR,
@@ -1479,6 +1496,90 @@
return IRQ_HANDLED;
}
+static int dwc3_msm_power_get_property_usb(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct dwc3_msm *mdwc = container_of(psy, struct dwc3_msm,
+ usb_psy);
+ switch (psp) {
+ case POWER_SUPPLY_PROP_SCOPE:
+ val->intval = mdwc->host_mode;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ val->intval = mdwc->current_max;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = mdwc->vbus_active;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = mdwc->online;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int dwc3_msm_power_set_property_usb(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ static bool init;
+ struct dwc3_msm *mdwc = container_of(psy, struct dwc3_msm,
+ usb_psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_SCOPE:
+ mdwc->host_mode = val->intval;
+ break;
+ /* Process PMIC notification in PRESENT prop */
+ case POWER_SUPPLY_PROP_PRESENT:
+ dev_dbg(mdwc->dev, "%s: notify xceiv event\n", __func__);
+ if (mdwc->otg_xceiv && (mdwc->ext_xceiv.otg_capability ||
+ !init)) {
+ mdwc->ext_xceiv.bsv = val->intval;
+ mdwc->ext_xceiv.id = DWC3_ID_FLOAT;
+ if (atomic_read(&mdwc->in_lpm)) {
+ dev_dbg(mdwc->dev,
+ "%s received in LPM\n", __func__);
+ queue_delayed_work(system_nrt_wq,
+ &mdwc->resume_work, 0);
+ } else {
+ mdwc->ext_xceiv.notify_ext_events(
+ mdwc->otg_xceiv->otg,
+ DWC3_EVENT_XCEIV_STATE);
+ }
+ }
+ if (!init)
+ init = true;
+ mdwc->vbus_active = val->intval;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ mdwc->online = val->intval;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ mdwc->current_max = val->intval;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ power_supply_changed(&mdwc->usb_psy);
+ return 0;
+}
+
+static char *dwc3_msm_pm_power_supplied_to[] = {
+ "battery",
+};
+
+static enum power_supply_property dwc3_msm_pm_power_props_usb[] = {
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_SCOPE,
+};
+
static int __devinit dwc3_msm_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
@@ -1639,19 +1740,24 @@
goto free_hs_ldo_init;
}
- /* DWC3 has separate IRQ line for OTG events (ID/BSV etc.) */
- msm->hs_phy_irq = platform_get_irq_byname(pdev, "hs_phy_irq");
- if (msm->hs_phy_irq < 0) {
- dev_dbg(&pdev->dev, "platform_get_irq for hs_phy_irq failed\n");
- msm->hs_phy_irq = 0;
- } else {
- ret = request_irq(msm->hs_phy_irq, msm_dwc3_irq,
- IRQF_TRIGGER_RISING, "msm_dwc3", msm);
- if (ret) {
- dev_err(&pdev->dev, "request irq failed (HSPHY INT)\n");
- goto disable_hs_ldo;
+ msm->ext_xceiv.otg_capability = of_property_read_bool(node,
+ "qcom,dwc-usb3-msm-otg-capability");
+
+ if (!msm->ext_xceiv.otg_capability) {
+ /* DWC3 has separate IRQ line for OTG events (ID/BSV etc.) */
+ msm->hs_phy_irq = platform_get_irq_byname(pdev, "hs_phy_irq");
+ if (msm->hs_phy_irq < 0) {
+ dev_dbg(&pdev->dev, "pget_irq for hs_phy_irq failed\n");
+ msm->hs_phy_irq = 0;
+ } else {
+ ret = request_irq(msm->hs_phy_irq, msm_dwc3_irq,
+ IRQF_TRIGGER_RISING, "msm_dwc3", msm);
+ if (ret) {
+ dev_err(&pdev->dev, "irqreq HSPHYINT failed\n");
+ goto disable_hs_ldo;
+ }
+ enable_irq_wake(msm->hs_phy_irq);
}
- enable_irq_wake(msm->hs_phy_irq);
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -1742,17 +1848,35 @@
goto put_pdev;
}
+ msm->usb_psy.name = "usb";
+ msm->usb_psy.type = POWER_SUPPLY_TYPE_USB;
+ msm->usb_psy.supplied_to = dwc3_msm_pm_power_supplied_to;
+ msm->usb_psy.num_supplicants = ARRAY_SIZE(
+ dwc3_msm_pm_power_supplied_to);
+ msm->usb_psy.properties = dwc3_msm_pm_power_props_usb;
+ msm->usb_psy.num_properties = ARRAY_SIZE(dwc3_msm_pm_power_props_usb);
+ msm->usb_psy.get_property = dwc3_msm_power_get_property_usb;
+ msm->usb_psy.set_property = dwc3_msm_power_set_property_usb;
+
+ ret = power_supply_register(&pdev->dev, &msm->usb_psy);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "%s:power_supply_register usb failed\n",
+ __func__);
+ goto put_pdev;
+ }
+
ret = platform_device_add_resources(dwc3, pdev->resource,
pdev->num_resources);
if (ret) {
dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
- goto put_pdev;
+ goto put_psupply;
}
ret = platform_device_add(dwc3);
if (ret) {
dev_err(&pdev->dev, "failed to register dwc3 device\n");
- goto put_pdev;
+ goto put_psupply;
}
msm->bus_scale_table = msm_bus_cl_get_pdata(pdev);
@@ -1805,6 +1929,8 @@
put_xcvr:
usb_put_transceiver(msm->otg_xceiv);
platform_device_del(dwc3);
+put_psupply:
+ power_supply_unregister(&msm->usb_psy);
put_pdev:
platform_device_put(dwc3);
free_hsphy_irq:
@@ -1906,9 +2032,14 @@
pm_runtime_enable(dev);
/* Let OTG know about resume event and update pm_count */
- if (mdwc->otg_xceiv)
+ if (mdwc->otg_xceiv) {
mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
DWC3_EVENT_PHY_RESUME);
+ if (mdwc->ext_xceiv.otg_capability)
+ mdwc->ext_xceiv.notify_ext_events(
+ mdwc->otg_xceiv->otg,
+ DWC3_EVENT_XCEIV_STATE);
+ }
}
return ret;
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index f96b88a..1aa8519 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -25,6 +25,9 @@
static void dwc3_otg_reset(struct dwc3_otg *dotg);
+static void dwc3_otg_notify_host_mode(struct usb_otg *otg, int host_mode);
+static void dwc3_otg_reset(struct dwc3_otg *dotg);
+
/**
* dwc3_otg_set_host_regs - reset dwc3 otg registers to host operation.
*
@@ -124,6 +127,7 @@
return ret;
}
+ dwc3_otg_notify_host_mode(otg, on);
ret = regulator_enable(dotg->vbus_otg);
if (ret) {
dev_err(otg->phy->dev, "unable to enable vbus_otg\n");
@@ -143,6 +147,7 @@
dev_err(otg->phy->dev, "unable to disable vbus_otg\n");
return ret;
}
+ dwc3_otg_notify_host_mode(otg, on);
/* re-init core and OTG register as XHCI reset clears it */
dwc3_post_host_reset_core_init(dotg->dwc);
@@ -290,9 +295,11 @@
static void dwc3_ext_event_notify(struct usb_otg *otg,
enum dwc3_ext_events event)
{
+ static bool init;
struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv;
struct usb_phy *phy = dotg->otg.phy;
+ int ret = 0;
if (event == DWC3_EVENT_PHY_RESUME) {
if (!pm_runtime_status_suspended(phy->dev)) {
@@ -300,7 +307,16 @@
} else {
dev_dbg(phy->dev, "ext PHY_RESUME event received\n");
/* ext_xceiver would have taken h/w out of LPM by now */
- pm_runtime_get(phy->dev);
+ ret = pm_runtime_get(phy->dev);
+ if (ret == -EACCES) {
+ /* pm_runtime_get may fail during system
+ resume with -EACCES error */
+ pm_runtime_disable(phy->dev);
+ pm_runtime_set_active(phy->dev);
+ pm_runtime_enable(phy->dev);
+ } else if (ret < 0) {
+ dev_warn(phy->dev, "pm_runtime_get failed!\n");
+ }
}
} else if (event == DWC3_EVENT_XCEIV_STATE) {
if (ext_xceiv->id == DWC3_ID_FLOAT)
@@ -308,11 +324,20 @@
else
clear_bit(ID, &dotg->inputs);
- if (ext_xceiv->bsv)
+ if (ext_xceiv->bsv) {
+ dev_dbg(phy->dev, "XCVR: BSV set\n");
set_bit(B_SESS_VLD, &dotg->inputs);
- else
+ } else {
+ dev_dbg(phy->dev, "XCVR: BSV clear\n");
clear_bit(B_SESS_VLD, &dotg->inputs);
+ }
+ if (!init) {
+ init = true;
+ complete(&dotg->dwc3_xcvr_vbus_init);
+ dev_dbg(phy->dev, "XCVR: BSV init complete\n");
+ return;
+ }
schedule_work(&dotg->sm_work);
}
}
@@ -335,6 +360,72 @@
return 0;
}
+static void dwc3_otg_notify_host_mode(struct usb_otg *otg, int host_mode)
+{
+ struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+
+ if (!dotg->psy) {
+ dev_err(otg->phy->dev, "no usb power supply registered\n");
+ return;
+ }
+
+ if (host_mode)
+ power_supply_set_scope(dotg->psy, POWER_SUPPLY_SCOPE_SYSTEM);
+ else
+ power_supply_set_scope(dotg->psy, POWER_SUPPLY_SCOPE_DEVICE);
+}
+
+static int dwc3_otg_set_power(struct usb_phy *phy, unsigned mA)
+{
+ static int power_supply_type;
+ struct dwc3_otg *dotg = container_of(phy->otg, struct dwc3_otg, otg);
+
+
+ if (!dotg->psy) {
+ dev_err(phy->dev, "no usb power supply registered\n");
+ return 0;
+ }
+
+ if (dotg->charger->chg_type == DWC3_SDP_CHARGER)
+ power_supply_type = POWER_SUPPLY_TYPE_USB;
+ else if (dotg->charger->chg_type == DWC3_CDP_CHARGER)
+ power_supply_type = POWER_SUPPLY_TYPE_USB_CDP;
+ else if (dotg->charger->chg_type == DWC3_DCP_CHARGER)
+ power_supply_type = POWER_SUPPLY_TYPE_USB_DCP;
+ else
+ power_supply_type = POWER_SUPPLY_TYPE_BATTERY;
+
+ power_supply_set_supply_type(dotg->psy, power_supply_type);
+
+ if (dotg->charger->max_power == mA)
+ return 0;
+
+ dev_info(phy->dev, "Avail curr from USB = %u\n", mA);
+
+ if (dotg->charger->max_power <= 2 && mA > 2) {
+ /* Enable charging */
+ if (power_supply_set_online(dotg->psy, true))
+ goto psy_error;
+ if (power_supply_set_current_limit(dotg->psy, 1000*mA))
+ goto psy_error;
+ } else if (dotg->charger->max_power > 0 && (mA == 0 || mA == 2)) {
+ /* Disable charging */
+ if (power_supply_set_online(dotg->psy, false))
+ goto psy_error;
+ /* Set max current limit */
+ if (power_supply_set_current_limit(dotg->psy, 0))
+ goto psy_error;
+ }
+
+ power_supply_changed(dotg->psy);
+ dotg->charger->max_power = mA;
+ return 0;
+
+psy_error:
+ dev_dbg(phy->dev, "power supply error when setting property\n");
+ return -ENXIO;
+}
+
/* IRQs which OTG driver is interested in handling */
#define DWC3_OEVT_MASK (DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT | \
DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT)
@@ -401,23 +492,32 @@
{
u32 osts = dwc3_readl(dotg->regs, DWC3_OSTS);
struct usb_phy *phy = dotg->otg.phy;
-
- /*
- * TODO: If using external notifications then wait here till initial
- * state is reported
- */
+ struct dwc3_ext_xceiv *ext_xceiv;
+ int ret;
dev_dbg(phy->dev, "Initialize OTG inputs, osts: 0x%x\n", osts);
- if (osts & DWC3_OTG_OSTS_CONIDSTS)
- set_bit(ID, &dotg->inputs);
- else
- clear_bit(ID, &dotg->inputs);
+ /*
+ * VBUS initial state is reported after PMIC
+ * driver initialization. Wait for it.
+ */
+ ret = wait_for_completion_timeout(&dotg->dwc3_xcvr_vbus_init, HZ * 5);
+ if (!ret)
+ dev_err(phy->dev, "%s: completion timeout\n", __func__);
- if (osts & DWC3_OTG_OSTS_BSESVALID)
- set_bit(B_SESS_VLD, &dotg->inputs);
- else
- clear_bit(B_SESS_VLD, &dotg->inputs);
+ ext_xceiv = dotg->ext_xceiv;
+ dwc3_otg_reset(dotg);
+ if (ext_xceiv && !ext_xceiv->otg_capability) {
+ if (osts & DWC3_OTG_OSTS_CONIDSTS)
+ set_bit(ID, &dotg->inputs);
+ else
+ clear_bit(ID, &dotg->inputs);
+
+ if (osts & DWC3_OTG_OSTS_BSESVALID)
+ set_bit(B_SESS_VLD, &dotg->inputs);
+ else
+ clear_bit(B_SESS_VLD, &dotg->inputs);
+ }
}
/**
@@ -442,6 +542,14 @@
switch (phy->state) {
case OTG_STATE_UNDEFINED:
dwc3_otg_init_sm(dotg);
+ if (!dotg->psy) {
+ dotg->psy = power_supply_get_by_name("usb");
+
+ if (!dotg->psy)
+ dev_err(phy->dev,
+ "couldn't get usb power supply\n");
+ }
+
/* Switch to A or B-Device according to ID / BSV */
if (!test_bit(ID, &dotg->inputs)) {
dev_dbg(phy->dev, "!id\n");
@@ -478,9 +586,13 @@
switch (charger->chg_type) {
case DWC3_DCP_CHARGER:
dev_dbg(phy->dev, "lpm, DCP charger\n");
+ dwc3_otg_set_power(phy,
+ DWC3_IDEV_CHG_MAX);
pm_runtime_put_sync(phy->dev);
break;
case DWC3_CDP_CHARGER:
+ dwc3_otg_set_power(phy,
+ DWC3_IDEV_CHG_MAX);
dwc3_otg_start_peripheral(&dotg->otg,
1);
phy->state = OTG_STATE_B_PERIPHERAL;
@@ -521,6 +633,7 @@
charger->chg_type =
DWC3_INVALID_CHARGER;
}
+ dwc3_otg_set_power(phy, 0);
dev_dbg(phy->dev, "No device, trying to suspend\n");
pm_runtime_put_sync(phy->dev);
}
@@ -587,6 +700,8 @@
static void dwc3_otg_reset(struct dwc3_otg *dotg)
{
static int once;
+ struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv;
+
/*
* OCFG[2] - OTG-Version = 1
* OCFG[1] - HNPCap = 0
@@ -612,9 +727,10 @@
dwc3_writel(dotg->regs, DWC3_OEVT, 0xFFFF);
/* Enable ID/BSV StsChngEn event*/
- dwc3_writel(dotg->regs, DWC3_OEVTEN,
- DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT |
- DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT);
+ if (ext_xceiv && !ext_xceiv->otg_capability)
+ dwc3_writel(dotg->regs, DWC3_OEVTEN,
+ DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT |
+ DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT);
}
/**
@@ -687,6 +803,7 @@
dotg->dwc = dwc;
dotg->otg.phy->otg = &dotg->otg;
dotg->otg.phy->dev = dwc->dev;
+ dotg->otg.phy->set_power = dwc3_otg_set_power;
ret = usb_set_transceiver(dotg->otg.phy);
if (ret) {
@@ -696,10 +813,9 @@
goto err2;
}
- dwc3_otg_reset(dotg);
-
dotg->otg.phy->state = OTG_STATE_UNDEFINED;
+ init_completion(&dotg->dwc3_xcvr_vbus_init);
INIT_WORK(&dotg->sm_work, dwc3_otg_sm_work);
ret = request_irq(dotg->irq, dwc3_otg_interrupt, IRQF_SHARED,
diff --git a/drivers/usb/dwc3/dwc3_otg.h b/drivers/usb/dwc3/dwc3_otg.h
index dd4cdf4..4384888 100644
--- a/drivers/usb/dwc3/dwc3_otg.h
+++ b/drivers/usb/dwc3/dwc3_otg.h
@@ -17,9 +17,12 @@
#define __LINUX_USB_DWC3_OTG_H
#include <linux/workqueue.h>
+#include <linux/power_supply.h>
#include <linux/usb/otg.h>
+#define DWC3_IDEV_CHG_MAX 1500
+
struct dwc3_charger;
/**
@@ -43,6 +46,8 @@
#define ID 0
#define B_SESS_VLD 1
unsigned long inputs;
+ struct power_supply *psy;
+ struct completion dwc3_xcvr_vbus_init;
};
/**
@@ -64,6 +69,7 @@
struct dwc3_charger {
enum dwc3_chg_type chg_type;
+ unsigned max_power;
/* start/stop charger detection, provided by external charger module */
void (*start_detection)(struct dwc3_charger *charger, bool start);
@@ -91,6 +97,7 @@
struct dwc3_ext_xceiv {
enum dwc3_id_state id;
bool bsv;
+ bool otg_capability;
/* to notify OTG about LPM exit event, provided by OTG */
void (*notify_ext_events)(struct usb_otg *otg,
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 451de18..9c1ebf8 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1455,6 +1455,17 @@
return 0;
}
+static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned mA)
+{
+ struct dwc3 *dwc = gadget_to_dwc(g);
+ struct dwc3_otg *dotg = dwc->dotg;
+
+ if (dotg && dotg->otg.phy)
+ return usb_phy_set_power(dotg->otg.phy, mA);
+
+ return -ENOTSUPP;
+}
+
static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
{
struct dwc3 *dwc = gadget_to_dwc(g);
@@ -1658,6 +1669,7 @@
.wakeup = dwc3_gadget_wakeup,
.set_selfpowered = dwc3_gadget_set_selfpowered,
.vbus_session = dwc3_gadget_vbus_session,
+ .vbus_draw = dwc3_gadget_vbus_draw,
.pullup = dwc3_gadget_pullup,
.udc_start = dwc3_gadget_start,
.udc_stop = dwc3_gadget_stop,
@@ -2083,6 +2095,7 @@
static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
{
u32 reg;
+ struct dwc3_otg *dotg = dwc->dotg;
dev_vdbg(dwc->dev, "%s\n", __func__);
@@ -2127,6 +2140,9 @@
dwc3_gadget_usb3_phy_suspend(dwc, false);
}
+ if (dotg && dotg->otg.phy)
+ usb_phy_set_power(dotg->otg.phy, 0);
+
if (dwc->gadget.speed != USB_SPEED_UNKNOWN)
dwc3_disconnect_gadget(dwc);
@@ -2334,6 +2350,13 @@
}
}
+ if (next == DWC3_LINK_STATE_U0) {
+ if (dwc->link_state == DWC3_LINK_STATE_U3)
+ dwc->gadget_driver->resume(&dwc->gadget);
+ } else if (next == DWC3_LINK_STATE_U3) {
+ dwc->gadget_driver->suspend(&dwc->gadget);
+ }
+
dwc->link_state = next;
dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index fa1bf43..9c7b1ec 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -75,7 +75,7 @@
*****************************************************************************/
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-#define ATDTW_SET_DELAY 100 /* 100msec delay */
+#define USB_MAX_TIMEOUT 100 /* 100msec timeout */
#define EP_PRIME_CHECK_DELAY (jiffies + msecs_to_jiffies(1000))
#define MAX_PRIME_CHECK_RETRY 3 /*Wait for 3sec for EP prime failure */
@@ -177,7 +177,8 @@
/* maximum number of enpoints: valid only after hw_device_reset() */
static unsigned hw_ep_max;
-
+static void dbg_usb_op_fail(u8 addr, const char *name,
+ const struct ci13xxx_ep *mep);
/**
* hw_ep_bit: calculates the bit number
* @num: endpoint number
@@ -381,6 +382,27 @@
return 0;
}
+static void debug_ept_flush_info(int ep_num, int dir)
+{
+ struct ci13xxx *udc = _udc;
+ struct ci13xxx_ep *mep;
+
+ if (dir)
+ mep = &udc->ci13xxx_ep[ep_num + hw_ep_max/2];
+ else
+ mep = &udc->ci13xxx_ep[ep_num];
+
+ pr_err_ratelimited("USB Registers\n");
+ pr_err_ratelimited("USBCMD:%x\n", hw_cread(CAP_USBCMD, ~0));
+ pr_err_ratelimited("USBSTS:%x\n", hw_cread(CAP_USBSTS, ~0));
+ pr_err_ratelimited("ENDPTLISTADDR:%x\n",
+ hw_cread(CAP_ENDPTLISTADDR, ~0));
+ pr_err_ratelimited("PORTSC:%x\n", hw_cread(CAP_PORTSC, ~0));
+ pr_err_ratelimited("USBMODE:%x\n", hw_cread(CAP_USBMODE, ~0));
+ pr_err_ratelimited("ENDPTSTAT:%x\n", hw_cread(CAP_ENDPTSTAT, ~0));
+
+ dbg_usb_op_fail(0xFF, "FLUSHF", mep);
+}
/**
* hw_ep_flush: flush endpoint fifo (execute without interruption)
* @num: endpoint number
@@ -390,13 +412,25 @@
*/
static int hw_ep_flush(int num, int dir)
{
+ ktime_t start, diff;
int n = hw_ep_bit(num, dir);
+ start = ktime_get();
do {
/* flush any pending transfer */
hw_cwrite(CAP_ENDPTFLUSH, BIT(n), BIT(n));
- while (hw_cread(CAP_ENDPTFLUSH, BIT(n)))
+ while (hw_cread(CAP_ENDPTFLUSH, BIT(n))) {
cpu_relax();
+ diff = ktime_sub(ktime_get(), start);
+ if (ktime_to_ms(diff) > USB_MAX_TIMEOUT) {
+ printk_ratelimited(KERN_ERR
+ "%s: Failed to flush ep#%d %s\n",
+ __func__, num,
+ dir ? "IN" : "OUT");
+ debug_ept_flush_info(num, dir);
+ return 0;
+ }
+ }
} while (hw_cread(CAP_ENDPTSTAT, BIT(n)));
return 0;
@@ -1006,29 +1040,30 @@
}
/**
- * dbg_prime_fail: prints a PRIME FAIL event
+ * dbg_usb_op_fail: prints USB Operation FAIL event
* @addr: endpoint address
* @mEp: endpoint structure
*/
-static void dbg_prime_fail(u8 addr, const char *name,
- const struct ci13xxx_ep *mEp)
+static void dbg_usb_op_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) {
+ if (mep != NULL) {
scnprintf(msg, sizeof(msg),
- "PRIME fail EP%d%s QH:%08X",
- mEp->num, mEp->dir ? "IN" : "OUT", mEp->qh.ptr->cap);
+ "%s Fail EP%d%s QH:%08X",
+ name, 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);
+ 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) {
+ list_for_each(ptr, &mep->qh.queue) {
req = list_entry(ptr, struct ci13xxx_req, queue);
scnprintf(msg, sizeof(msg),
"%08X:%08X:%08X\n",
@@ -1703,52 +1738,52 @@
static void ep_prime_timer_func(unsigned long data)
{
- struct ci13xxx_ep *mEp = (struct ci13xxx_ep *)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);
+ int n = hw_ep_bit(mep->num, mep->dir);
unsigned long flags;
- spin_lock_irqsave(mEp->lock, flags);
+ spin_lock_irqsave(mep->lock, flags);
if (!hw_cread(CAP_ENDPTPRIME, BIT(n)))
goto out;
- if (list_empty(&mEp->qh.queue))
+ if (list_empty(&mep->qh.queue))
goto out;
- req = list_entry(mEp->qh.queue.next, struct ci13xxx_req, queue);
+ 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;
+ 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) {
+ 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++;
+ dbg_usb_op_fail(0xFF, "PRIMEF", mep);
+ mep->prime_fail_count++;
} else {
- mod_timer(&mEp->prime_timer, EP_PRIME_CHECK_DELAY);
+ mod_timer(&mep->prime_timer, EP_PRIME_CHECK_DELAY);
}
- spin_unlock_irqrestore(mEp->lock, flags);
+ spin_unlock_irqrestore(mep->lock, flags);
return;
out:
- mEp->prime_timer_count = 0;
- spin_unlock_irqrestore(mEp->lock, flags);
+ mep->prime_timer_count = 0;
+ spin_unlock_irqrestore(mep->lock, flags);
}
@@ -1874,7 +1909,7 @@
tmp_stat = hw_cread(CAP_ENDPTSTAT, BIT(n));
diff = ktime_sub(ktime_get(), start);
/* poll for max. 100ms */
- if (ktime_to_ms(diff) > ATDTW_SET_DELAY) {
+ if (ktime_to_ms(diff) > USB_MAX_TIMEOUT) {
if (hw_cread(CAP_USBCMD, USBCMD_ATDTW))
break;
printk_ratelimited(KERN_ERR
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 681435a..729910d 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -541,9 +541,7 @@
unsigned long flags;
int ret;
- int notif_c = 0;
-
- pr_info("dev:%p portno#%d\n", dev, dev->port_num);
+ pr_debug("dev:%p portno#%d\n", dev, dev->port_num);
spin_lock_irqsave(&dev->lock, flags);
@@ -565,8 +563,12 @@
return;
}
- notif_c = atomic_inc_return(&dev->not_port.notify_count);
- pr_info("atomic_inc_return[notif_c] = %d", notif_c);
+ if (atomic_inc_return(&dev->not_port.notify_count) != 1) {
+ pr_debug("delay ep_queue: notifications queue is busy[%d]",
+ atomic_read(&dev->not_port.notify_count));
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return;
+ }
event = req->buf;
event->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
@@ -577,8 +579,6 @@
event->wLength = cpu_to_le16(0);
spin_unlock_irqrestore(&dev->lock, flags);
- pr_info("Call usb_ep_queue");
-
ret = usb_ep_queue(dev->not_port.notify,
dev->not_port.notify_req, GFP_ATOMIC);
if (ret) {
@@ -586,7 +586,7 @@
pr_err("ep enqueue error %d\n", ret);
}
- pr_info("Succcessfull Exit");
+ pr_debug("Successful Exit");
}
static int
@@ -672,7 +672,6 @@
mbim->ntb_input_size = NTB_DEFAULT_IN_SIZE;
- atomic_set(&mbim->not_port.notify_count, 0);
atomic_set(&mbim->online, 0);
}
@@ -750,6 +749,21 @@
switch (mbim->not_port.notify_state) {
case NCM_NOTIFY_NONE:
+ pr_debug("Notification %02x sent\n", event->bNotificationType);
+
+ if (atomic_read(&mbim->not_port.notify_count) <= 0) {
+ pr_debug("notify_none: done");
+ return;
+ }
+
+ spin_unlock(&mbim->lock);
+ status = usb_ep_queue(mbim->not_port.notify, req, GFP_ATOMIC);
+ spin_lock(&mbim->lock);
+ if (status) {
+ atomic_dec(&mbim->not_port.notify_count);
+ pr_err("Queue notify request failed, err: %d", status);
+ }
+
return;
case NCM_NOTIFY_CONNECT:
@@ -782,20 +796,22 @@
mbim->not_port.notify_state = NCM_NOTIFY_CONNECT;
break;
}
+
event->bmRequestType = 0xA1;
event->wIndex = cpu_to_le16(mbim->ctrl_id);
- mbim->not_port.notify_req = NULL;
/*
* In double buffering if there is a space in FIFO,
* completion callback can be called right after the call,
* so unlocking
*/
+ atomic_inc(&mbim->not_port.notify_count);
+ pr_debug("queue request: notify_count = %d",
+ atomic_read(&mbim->not_port.notify_count));
spin_unlock(&mbim->lock);
status = usb_ep_queue(mbim->not_port.notify, req, GFP_ATOMIC);
spin_lock(&mbim->lock);
- if (status < 0) {
- mbim->not_port.notify_req = req;
+ if (status) {
atomic_dec(&mbim->not_port.notify_count);
pr_err("usb_ep_queue failed, err: %d", status);
}
@@ -822,27 +838,14 @@
struct f_mbim *mbim = req->context;
struct usb_cdc_notification *event = req->buf;
- int notif_c = 0;
-
- pr_info("dev:%p\n", mbim);
+ pr_debug("dev:%p\n", mbim);
spin_lock(&mbim->lock);
switch (req->status) {
case 0:
- pr_info("Notification %02x sent\n",
- event->bNotificationType);
-
- notif_c = atomic_dec_return(&mbim->not_port.notify_count);
-
- if (notif_c != 0) {
- pr_info("Continue to mbim_do_notify()");
- break;
- } else {
- pr_info("notify_count decreased to 0. Do not notify");
- spin_unlock(&mbim->lock);
- return;
- }
-
+ atomic_dec(&mbim->not_port.notify_count);
+ pr_debug("notify_count = %d",
+ atomic_read(&mbim->not_port.notify_count));
break;
case -ECONNRESET:
@@ -862,9 +865,7 @@
break;
}
- mbim->not_port.notify_req = req;
mbim_do_notify(mbim);
-
spin_unlock(&mbim->lock);
pr_info("dev:%p Exit\n", mbim);
@@ -1308,12 +1309,13 @@
pr_info("Set mbim port out_desc = 0x%p",
mbim->bam_port.out->desc);
+
+ pr_debug("Activate mbim\n");
+ mbim_bam_connect(mbim);
+
} else {
pr_info("PORTS already SET");
}
-
- pr_info("Activate mbim\n");
- mbim_bam_connect(mbim);
}
spin_lock(&mbim->lock);
@@ -1368,6 +1370,8 @@
mbim->not_port.notify->driver_data = NULL;
}
+ atomic_set(&mbim->not_port.notify_count, 0);
+
pr_info("mbim deactivated\n");
}
@@ -1789,7 +1793,6 @@
spin_lock(&_mbim_dev->lock);
_mbim_dev->is_open = true;
- mbim_notify(_mbim_dev);
spin_unlock(&_mbim_dev->lock);
pr_info("Exit, mbim file opened\n");
@@ -1805,7 +1808,6 @@
spin_lock(&mbim->lock);
mbim->is_open = false;
- mbim_notify(mbim);
spin_unlock(&mbim->lock);
mbim_unlock(&_mbim_dev->open_excl);
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index c7f9e55..25da094 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -2838,15 +2838,7 @@
mfd->start_histogram = mdp_histogram_start;
mfd->stop_histogram = mdp_histogram_stop;
mdp4_display_intf_sel(if_no, DSI_CMD_INTF);
-
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- spin_lock_irqsave(&mdp_spin_lock, flag);
- mdp_intr_mask |= INTR_OVERLAY0_DONE;
- outp32(MDP_INTR_ENABLE, mdp_intr_mask);
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
#else
-
mfd->dma_fnc = mdp_dma2_update;
mfd->do_histogram = mdp_do_histogram;
mfd->start_histogram = mdp_histogram_start;
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 7c87c44..1bd697e 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -1632,8 +1632,14 @@
data |= stage;
}
+ /*
+ * stage_commit may be called from overlay_unset
+ * for command panel, mdp clocks may be off at this time.
+ * so mdp clock enabled is necessary
+ */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
mdp_clk_ctrl(1);
+
mdp4_mixer_blend_setup(mixer);
off = 0;
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index c5442a7..10410a7 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -31,14 +31,14 @@
#include "mipi_dsi.h"
#include "mdp4.h"
-static int dsi_state;
-
-#define TOUT_PERIOD HZ /* 1 second */
-#define MS_100 (HZ/10) /* 100 ms */
-
static int vsync_start_y_adjust = 4;
#define MAX_CONTROLLER 1
+
+/*
+ * VSYNC_EXPIRE_TICK == 0 means clock always on
+ * VSYNC_EXPIRE_TICK == 4 is recommended
+ */
#define VSYNC_EXPIRE_TICK 4
static struct vsycn_ctrl {
@@ -51,10 +51,10 @@
u32 ov_done;
u32 dmap_koff;
u32 dmap_done;
+ u32 pan_display;
uint32 rdptr_intr_tot;
uint32 rdptr_sirq_tot;
atomic_t suspend;
- atomic_t vsync_resume;
int wait_vsync_cnt;
int blt_change;
int blt_free;
@@ -71,7 +71,6 @@
int vsync_enabled;
int clk_enabled;
int clk_control;
- int new_update;
ktime_t vsync_time;
struct work_struct clk_work;
} vsync_ctrl_db[MAX_CONTROLLER];
@@ -229,8 +228,10 @@
vctrl = &vsync_ctrl_db[cndx];
- if (atomic_read(&vctrl->suspend) > 0)
+ if (atomic_read(&vctrl->suspend)) {
+ pr_err("%s: suspended, no more pipe queue\n", __func__);
return;
+ }
mutex_lock(&vctrl->update_lock);
undx = vctrl->update_ndx;
@@ -363,12 +364,14 @@
mdp4_dsi_cmd_blt_ov_update(pipe);
pipe->ov_cnt++;
vctrl->ov_koff++;
+ INIT_COMPLETION(vctrl->ov_comp);
vsync_irq_enable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM);
} else {
+ INIT_COMPLETION(vctrl->dmap_comp);
vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
vctrl->dmap_koff++;
}
- pr_debug("%s: kickoff\n", __func__);
+ pr_debug("%s: kickoff, pid=%d\n", __func__, current->pid);
/* kickoff overlay engine */
mdp4_stat.kickoff_ov0++;
outpdw(MDP_BASE + 0x0004, 0);
@@ -392,15 +395,14 @@
{
struct vsycn_ctrl *vctrl;
unsigned long flags;
- int clk_set_on = 0;
int cndx = 0;
+ int clk_set_on = 0;
vctrl = &vsync_ctrl_db[cndx];
- pr_debug("%s: clk_enabled=%d vsycn_enabeld=%d req=%d\n", __func__,
- vctrl->clk_enabled, vctrl->vsync_enabled, enable);
-
mutex_lock(&vctrl->update_lock);
+ pr_debug("%s: clk_enabled=%d vsync_enabled=%d req=%d\n", __func__,
+ vctrl->clk_enabled, vctrl->vsync_enabled, enable);
if (vctrl->vsync_enabled == enable) {
mutex_unlock(&vctrl->update_lock);
@@ -410,6 +412,10 @@
vctrl->vsync_enabled = enable;
if (enable) {
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ vctrl->clk_control = 0;
+ vctrl->expire_tick = 0;
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
if (vctrl->clk_enabled == 0) {
pr_debug("%s: SET_CLK_ON\n", __func__);
mipi_dsi_clk_cfg(1);
@@ -417,26 +423,16 @@
vctrl->clk_enabled = 1;
clk_set_on = 1;
}
- spin_lock_irqsave(&vctrl->spin_lock, flags);
- vctrl->clk_control = 0;
- vctrl->expire_tick = 0;
- vctrl->new_update = 1;
if (clk_set_on) {
vsync_irq_enable(INTR_PRIMARY_RDPTR,
MDP_PRIM_RDPTR_TERM);
}
- spin_unlock_irqrestore(&vctrl->spin_lock, flags);
} else {
spin_lock_irqsave(&vctrl->spin_lock, flags);
- vctrl->clk_control = 1;
- if (vctrl->clk_enabled)
- vctrl->expire_tick = VSYNC_EXPIRE_TICK;
+ vctrl->expire_tick = VSYNC_EXPIRE_TICK;
spin_unlock_irqrestore(&vctrl->spin_lock, flags);
}
mutex_unlock(&vctrl->update_lock);
-
- if (vctrl->vsync_enabled && atomic_read(&vctrl->suspend) == 0)
- atomic_set(&vctrl->vsync_resume, 1);
}
void mdp4_dsi_cmd_wait4vsync(int cndx, long long *vtime)
@@ -514,7 +510,8 @@
struct vsycn_ctrl *vctrl;
vctrl = &vsync_ctrl_db[cndx];
- pr_debug("%s: ISR, cpu=%d\n", __func__, smp_processor_id());
+ pr_debug("%s: ISR, tick=%d pan=%d cpu=%d\n", __func__,
+ vctrl->expire_tick, vctrl->pan_display, smp_processor_id());
vctrl->rdptr_intr_tot++;
spin_lock(&vctrl->spin_lock);
@@ -525,8 +522,15 @@
if (vctrl->expire_tick) {
vctrl->expire_tick--;
- if (vctrl->expire_tick == 0)
- schedule_work(&vctrl->clk_work);
+ if (vctrl->expire_tick == 0) {
+ if (vctrl->pan_display <= 0) {
+ vctrl->clk_control = 1;
+ schedule_work(&vctrl->clk_work);
+ } else {
+ /* wait one more vsycn */
+ vctrl->expire_tick += 1;
+ }
+ }
}
spin_unlock(&vctrl->spin_lock);
}
@@ -546,11 +550,15 @@
spin_lock(&vctrl->spin_lock);
vsync_irq_disable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
vctrl->dmap_done++;
+
+ if (vctrl->pan_display)
+ vctrl->pan_display--;
+
diff = vctrl->ov_done - vctrl->dmap_done;
pr_debug("%s: ov_koff=%d ov_done=%d dmap_koff=%d dmap_done=%d cpu=%d\n",
__func__, vctrl->ov_koff, vctrl->ov_done, vctrl->dmap_koff,
vctrl->dmap_done, smp_processor_id());
- complete_all(&vctrl->dmap_comp);
+ complete(&vctrl->dmap_comp);
if (diff <= 0) {
if (vctrl->blt_wait)
vctrl->blt_wait = 0;
@@ -586,7 +594,7 @@
spin_lock(&vctrl->spin_lock);
vsync_irq_disable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM);
vctrl->ov_done++;
- complete_all(&vctrl->ov_comp);
+ complete(&vctrl->ov_comp);
diff = vctrl->ov_done - vctrl->dmap_done;
pr_debug("%s: ov_koff=%d ov_done=%d dmap_koff=%d dmap_done=%d cpu=%d\n",
@@ -622,20 +630,24 @@
static void clk_ctrl_work(struct work_struct *work)
{
+ unsigned long flags;
struct vsycn_ctrl *vctrl =
container_of(work, typeof(*vctrl), clk_work);
- unsigned long flags;
mutex_lock(&vctrl->update_lock);
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
if (vctrl->clk_control && vctrl->clk_enabled) {
- pr_debug("%s: SET_CLK_OFF\n", __func__);
- mdp_clk_ctrl(0);
- mipi_dsi_clk_cfg(0);
- spin_lock_irqsave(&vctrl->spin_lock, flags);
vsync_irq_disable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM);
vctrl->clk_enabled = 0;
vctrl->clk_control = 0;
spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+ /* make sure dsi link is idle */
+ mipi_dsi_mdp_busy_wait();
+ mipi_dsi_clk_cfg(0);
+ mdp_clk_ctrl(0);
+ pr_debug("%s: SET_CLK_OFF, pid=%d\n", __func__, current->pid);
+ } else {
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
}
mutex_unlock(&vctrl->update_lock);
}
@@ -652,8 +664,7 @@
cndx = 0;
vctrl = &vsync_ctrl_db[0];
- if (atomic_read(&vctrl->suspend) > 0 ||
- atomic_read(&vctrl->vsync_resume) == 0)
+ if (atomic_read(&vctrl->suspend) > 0)
return 0;
spin_lock_irqsave(&vctrl->spin_lock, flags);
@@ -671,6 +682,8 @@
spin_unlock_irqrestore(&vctrl->spin_lock, flags);
ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", vsync_tick);
+ pr_debug("%s: UEVENT\n", __func__);
+
buf[strlen(buf) + 1] = '\0';
return ret;
}
@@ -695,7 +708,6 @@
init_completion(&vctrl->dmap_comp);
init_completion(&vctrl->vsync_comp);
spin_lock_init(&vctrl->spin_lock);
- atomic_set(&vctrl->vsync_resume, 1);
INIT_WORK(&vctrl->clk_work, clk_ctrl_work);
}
@@ -704,20 +716,6 @@
primary_rdptr_isr(0);
}
-void mdp4_overlay_dsi_state_set(int state)
-{
- unsigned long flag;
-
- spin_lock_irqsave(&mdp_spin_lock, flag);
- dsi_state = state;
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
-}
-
-int mdp4_overlay_dsi_state_get(void)
-{
- return dsi_state;
-}
-
static __u32 msm_fb_line_length(__u32 fb_index, __u32 xres, int bpp)
{
/*
@@ -942,6 +940,7 @@
pipe->srcp0_addr = (uint32)src;
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ mdp_clk_ctrl(1);
mdp4_overlay_rgb_setup(pipe);
@@ -957,6 +956,7 @@
mdp4_mixer_stage_commit(pipe->mixer_num);
/* MDP cmd block disable */
+ mdp_clk_ctrl(0);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
@@ -991,9 +991,10 @@
struct msm_fb_data_type *mfd;
struct vsycn_ctrl *vctrl;
- pr_debug("%s+:\n", __func__);
+ pr_debug("%s+: pid=%d\n", __func__, current->pid);
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+ mfd->cont_splash_done = 1;
vctrl = &vsync_ctrl_db[cndx];
vctrl->mfd = mfd;
@@ -1006,7 +1007,6 @@
mdp4_iommu_attach();
atomic_set(&vctrl->suspend, 0);
- pr_debug("%s-:\n", __func__);
if (!vctrl->sysfs_created) {
ret = sysfs_create_group(&vctrl->dev->kobj,
@@ -1022,6 +1022,8 @@
vctrl->sysfs_created = 1;
}
+ pr_debug("%s-:\n", __func__);
+
return ret;
}
@@ -1034,8 +1036,9 @@
struct mdp4_overlay_pipe *pipe;
struct vsync_update *vp;
int undx;
+ int need_wait, cnt;
- pr_debug("%s+:\n", __func__);
+ pr_debug("%s+: pid=%d\n", __func__, current->pid);
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
@@ -1046,26 +1049,40 @@
return ret;
}
+ need_wait = 0;
+ mutex_lock(&vctrl->update_lock);
atomic_set(&vctrl->suspend, 1);
- atomic_set(&vctrl->vsync_resume, 0);
complete_all(&vctrl->vsync_comp);
+ pr_debug("%s: clk=%d pan=%d\n", __func__,
+ vctrl->clk_enabled, vctrl->pan_display);
+ if (vctrl->clk_enabled)
+ need_wait = 1;
+ mutex_unlock(&vctrl->update_lock);
+
+ cnt = 0;
+ if (need_wait) {
+ while (vctrl->clk_enabled) {
+ msleep(20);
+ cnt++;
+ if (cnt > 10)
+ break;
+ }
+ }
+
+ /* message for system suspnded */
+ if (cnt > 10)
+ pr_err("%s:Error, mdp clocks NOT off\n", __func__);
+ else
+ pr_debug("%s: mdp clocks off at cnt=%d\n", __func__, cnt);
+
/* sanity check, free pipes besides base layer */
mdp4_overlay_unset_mixer(pipe->mixer_num);
mdp4_mixer_stage_down(pipe, 1);
mdp4_overlay_pipe_free(pipe);
vctrl->base_pipe = NULL;
- if (vctrl->clk_enabled) {
- /*
- * in case of suspend, vsycn_ctrl off is not
- * received from frame work which left clock on
- * then, clock need to be turned off here
- */
- mdp_clk_ctrl(0);
- }
-
undx = vctrl->update_ndx;
vp = &vctrl->vlist[undx];
if (vp->update_cnt) {
@@ -1076,23 +1093,7 @@
vp->update_cnt = 0; /* empty queue */
}
- vctrl->clk_enabled = 0;
- vctrl->vsync_enabled = 0;
- vctrl->clk_control = 0;
- vctrl->expire_tick = 0;
-
- vsync_irq_disable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM);
-
-
pr_debug("%s-:\n", __func__);
-
- /*
- * footswitch off
- * this will casue all mdp register
- * to be reset to default
- * after footswitch on later
- */
-
return ret;
}
@@ -1127,7 +1128,7 @@
struct vsycn_ctrl *vctrl;
struct mdp4_overlay_pipe *pipe;
unsigned long flags;
- long long tick;
+ int clk_set_on = 0;
mutex_lock(&mfd->dma->ov_mutex);
vctrl = &vsync_ctrl_db[cndx];
@@ -1145,25 +1146,32 @@
}
mutex_lock(&vctrl->update_lock);
- if (!vctrl->clk_enabled) {
- pr_err("%s: mdp clocks disabled\n", __func__);
+ if (atomic_read(&vctrl->suspend)) {
mutex_unlock(&vctrl->update_lock);
mutex_unlock(&mfd->dma->ov_mutex);
+ pr_err("%s: suspended, no more pan display\n", __func__);
return;
-
}
- mutex_unlock(&vctrl->update_lock);
spin_lock_irqsave(&vctrl->spin_lock, flags);
- if (vctrl->expire_tick) {
- /*
- * in the middle of shutting clocks down
- * delay to allow pan display to go through
- */
+ vctrl->clk_control = 0;
+ vctrl->pan_display++;
+ if (!vctrl->clk_enabled) {
+ clk_set_on = 1;
+ vctrl->clk_enabled = 1;
vctrl->expire_tick = VSYNC_EXPIRE_TICK;
}
spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+ if (clk_set_on) {
+ pr_debug("%s: SET_CLK_ON\n", __func__);
+ mipi_dsi_clk_cfg(1);
+ mdp_clk_ctrl(1);
+ vsync_irq_enable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM);
+ }
+
+ mutex_unlock(&vctrl->update_lock);
+
if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE) {
mdp4_mipi_vsync_enable(mfd, pipe, 0);
mdp4_overlay_setup_pipe_addr(mfd, pipe);
@@ -1172,8 +1180,6 @@
mdp4_overlay_mdp_perf_upd(mfd, 1);
mdp4_dsi_cmd_pipe_commit(cndx, 0);
- mdp4_dsi_cmd_wait4vsync(cndx, &tick);
mdp4_overlay_mdp_perf_upd(mfd, 0);
mutex_unlock(&mfd->dma->ov_mutex);
-
}
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 7f41221..c2d5f28 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -1173,7 +1173,7 @@
if (rc) {
DEV_ERR("%s: core hdmi_msm_enable_power failed rc = %d\n",
__func__, rc);
- goto disable_hpd_power;
+ return rc;
}
rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CEC_PM, 1);
if (rc) {
@@ -1185,8 +1185,6 @@
return rc;
disable_core_power:
hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CORE_PM, 0);
-disable_hpd_power:
- hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, 0);
return rc;
} /* hdmi_tx_core_on */
diff --git a/drivers/video/msm/mipi_dsi.c b/drivers/video/msm/mipi_dsi.c
index 7d534ed..a58010e 100644
--- a/drivers/video/msm/mipi_dsi.c
+++ b/drivers/video/msm/mipi_dsi.c
@@ -69,6 +69,8 @@
struct msm_fb_data_type *mfd;
struct msm_panel_info *pinfo;
+ pr_debug("%s+:\n", __func__);
+
mfd = platform_get_drvdata(pdev);
pinfo = &mfd->panel_info;
@@ -77,15 +79,14 @@
else
down(&mfd->dma->mutex);
- mdp4_overlay_dsi_state_set(ST_DSI_SUSPEND);
+ if (mfd->panel_info.type == MIPI_CMD_PANEL) {
+ mipi_dsi_prepare_clocks();
+ mipi_dsi_ahb_ctrl(1);
+ mipi_dsi_clk_enable();
- /* make sure dsi clk is on so that
- * dcs commands can be sent
- */
- mipi_dsi_clk_cfg(1);
-
- /* make sure dsi_cmd_mdp is idle */
- mipi_dsi_cmd_mdp_busy();
+ /* make sure dsi_cmd_mdp is idle */
+ mipi_dsi_cmd_mdp_busy();
+ }
/*
* Desctiption: change to DSI_CMD_MODE since it needed to
@@ -146,6 +147,8 @@
u32 dummy_xres, dummy_yres;
int target_type = 0;
+ pr_debug("%s+:\n", __func__);
+
mfd = platform_get_drvdata(pdev);
fbi = mfd->fbi;
var = &fbi->var;
@@ -305,14 +308,15 @@
}
mipi_dsi_set_tear_on(mfd);
}
+ mipi_dsi_clk_disable();
+ mipi_dsi_ahb_ctrl(0);
+ mipi_dsi_unprepare_clocks();
}
#ifdef CONFIG_MSM_BUS_SCALING
mdp_bus_scale_update_request(2);
#endif
- mdp4_overlay_dsi_state_set(ST_DSI_RESUME);
-
if (mdp_rev >= MDP_REV_41)
mutex_unlock(&mfd->dma->ov_mutex);
else
diff --git a/drivers/video/msm/mipi_dsi.h b/drivers/video/msm/mipi_dsi.h
index 0f37f6f..2711c1a 100644
--- a/drivers/video/msm/mipi_dsi.h
+++ b/drivers/video/msm/mipi_dsi.h
@@ -319,7 +319,7 @@
void mipi_dsi_post_kickoff_del(struct dsi_kickoff_action *act);
void mipi_dsi_controller_cfg(int enable);
void mipi_dsi_sw_reset(void);
-void mipi_dsi_mdp_busy_wait(struct msm_fb_data_type *mfd);
+void mipi_dsi_mdp_busy_wait(void);
irqreturn_t mipi_dsi_isr(int irq, void *ptr);
diff --git a/drivers/video/msm/mipi_dsi_host.c b/drivers/video/msm/mipi_dsi_host.c
index 60311dc..bea6b4e 100644
--- a/drivers/video/msm/mipi_dsi_host.c
+++ b/drivers/video/msm/mipi_dsi_host.c
@@ -50,6 +50,7 @@
static int dsi_ctrl_lock;
static int dsi_mdp_busy;
static struct mutex cmd_mutex;
+static struct mutex clk_mutex;
static struct list_head pre_kickoff_list;
static struct list_head post_kickoff_list;
@@ -99,6 +100,7 @@
spin_lock_init(&dsi_mdp_lock);
spin_lock_init(&dsi_clk_lock);
mutex_init(&cmd_mutex);
+ mutex_init(&clk_mutex);
INIT_LIST_HEAD(&pre_kickoff_list);
INIT_LIST_HEAD(&post_kickoff_list);
@@ -165,12 +167,12 @@
void mipi_dsi_clk_cfg(int on)
{
- unsigned long flags;
static int dsi_clk_cnt;
- spin_lock_irqsave(&mdp_spin_lock, flags);
+ mutex_lock(&clk_mutex);
if (on) {
if (dsi_clk_cnt == 0) {
+ mipi_dsi_prepare_clocks();
mipi_dsi_ahb_ctrl(1);
mipi_dsi_clk_enable();
}
@@ -181,10 +183,13 @@
if (dsi_clk_cnt == 0) {
mipi_dsi_clk_disable();
mipi_dsi_ahb_ctrl(0);
+ mipi_dsi_unprepare_clocks();
}
}
}
- spin_unlock_irqrestore(&mdp_spin_lock, flags);
+ pr_debug("%s: on=%d clk_cnt=%d pid=%d\n", __func__,
+ on, dsi_clk_cnt, current->pid);
+ mutex_unlock(&clk_mutex);
}
void mipi_dsi_turn_on_clks(void)
@@ -1022,31 +1027,13 @@
wmb();
}
-void mipi_dsi_mdp_busy_wait(struct msm_fb_data_type *mfd)
+void mipi_dsi_mdp_busy_wait(void)
{
- unsigned long flag;
- int need_wait = 0;
-
- pr_debug("%s: start pid=%d\n",
- __func__, current->pid);
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- if (dsi_mdp_busy == TRUE) {
- INIT_COMPLETION(dsi_mdp_comp);
- need_wait++;
- }
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
- if (need_wait) {
- /* wait until DMA finishes the current job */
- pr_debug("%s: pending pid=%d\n",
- __func__, current->pid);
- wait_for_completion(&dsi_mdp_comp);
- }
- pr_debug("%s: done pid=%d\n",
- __func__, current->pid);
+ mutex_lock(&cmd_mutex);
+ mipi_dsi_cmd_mdp_busy();
+ mutex_unlock(&cmd_mutex);
}
-
void mipi_dsi_cmd_mdp_start(void)
{
unsigned long flag;
@@ -1054,8 +1041,9 @@
mipi_dsi_mdp_stat_inc(STAT_DSI_START);
spin_lock_irqsave(&dsi_mdp_lock, flag);
- mipi_dsi_enable_irq(DSI_MDP_TERM);
- dsi_mdp_busy = TRUE;
+ mipi_dsi_enable_irq(DSI_MDP_TERM);
+ dsi_mdp_busy = TRUE;
+ INIT_COMPLETION(dsi_mdp_comp);
spin_unlock_irqrestore(&dsi_mdp_lock, flag);
}
@@ -1089,14 +1077,28 @@
void mipi_dsi_set_tear_on(struct msm_fb_data_type *mfd)
{
- mipi_dsi_buf_init(&dsi_tx_buf);
- mipi_dsi_cmds_tx(&dsi_tx_buf, &dsi_tear_on_cmd, 1);
+ struct dcs_cmd_req cmdreq;
+
+ cmdreq.cmds = &dsi_tear_on_cmd;
+ cmdreq.cmds_cnt = 1;
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+
+ mipi_dsi_cmdlist_put(&cmdreq);
}
void mipi_dsi_set_tear_off(struct msm_fb_data_type *mfd)
{
- mipi_dsi_buf_init(&dsi_tx_buf);
- mipi_dsi_cmds_tx(&dsi_tx_buf, &dsi_tear_off_cmd, 1);
+ struct dcs_cmd_req cmdreq;
+
+ cmdreq.cmds = &dsi_tear_off_cmd;
+ cmdreq.cmds_cnt = 1;
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+
+ mipi_dsi_cmdlist_put(&cmdreq);
}
int mipi_dsi_cmd_reg_tx(uint32 data)
@@ -1137,7 +1139,6 @@
struct dsi_cmd_desc *cm;
uint32 dsi_ctrl, ctrl;
int i, video_mode;
- unsigned long flag;
/* turn on cmd mode
* for video mode, do not send cmds more than
@@ -1151,10 +1152,6 @@
MIPI_OUTP(MIPI_DSI_BASE + 0x0000, ctrl);
}
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- dsi_mdp_busy = TRUE;
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
cm = cmds;
mipi_dsi_buf_init(tp);
for (i = 0; i < cnt; i++) {
@@ -1170,11 +1167,6 @@
if (video_mode)
MIPI_OUTP(MIPI_DSI_BASE + 0x0000, dsi_ctrl); /* restore */
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- dsi_mdp_busy = FALSE;
- complete(&dsi_mdp_comp);
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
return cnt;
}
@@ -1204,7 +1196,6 @@
{
int cnt, len, diff, pkt_size;
char cmd;
- unsigned long flag;
if (mfd->panel_info.mipi.no_max_pkt_size) {
/* Only support rlen = 4*n */
@@ -1241,10 +1232,6 @@
#endif
}
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- dsi_mdp_busy = TRUE;
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
if (!mfd->panel_info.mipi.no_max_pkt_size) {
/* packet size need to be set at every read */
pkt_size = len;
@@ -1279,11 +1266,6 @@
mipi_dsi_cmd_dma_rx(rp, cnt);
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- dsi_mdp_busy = FALSE;
- complete(&dsi_mdp_comp);
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
if (mfd->panel_info.mipi.no_max_pkt_size) {
/*
* remove extra 2 bytes from previous
@@ -1327,7 +1309,6 @@
struct dsi_cmd_desc *cmds;
int cnt, len, diff, pkt_size;
char cmd;
- unsigned long flag;
if (req->flags & CMD_REQ_NO_MAX_PKT_SIZE) {
/* Only support rlen = 4*n */
@@ -1359,10 +1340,6 @@
cnt = len + 6; /* 4 bytes header + 2 bytes crc */
}
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- dsi_mdp_busy = TRUE;
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
if (!(req->flags & CMD_REQ_NO_MAX_PKT_SIZE)) {
@@ -1399,11 +1376,6 @@
mipi_dsi_cmd_dma_rx(rp, cnt);
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- dsi_mdp_busy = FALSE;
- complete(&dsi_mdp_comp);
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
if (req->flags & CMD_REQ_NO_MAX_PKT_SIZE) {
/*
* remove extra 2 bytes from previous
@@ -1515,24 +1487,43 @@
return rlen;
}
-void mipi_dsi_cmd_mdp_busy(void)
+static void mipi_dsi_wait_for_video_eng_busy(void)
{
u32 status;
+ int sleep_us = 4000;
+
+ /*
+ * if video mode engine was not busy (in BLLP)
+ * wait to pass BLLP
+ */
+
+ /* check for VIDEO_MODE_ENGINE_BUSY */
+ readl_poll((MIPI_DSI_BASE + 0x0004), /* DSI_STATUS */
+ status,
+ (status & 0x08),
+ sleep_us);
+}
+
+void mipi_dsi_cmd_mdp_busy(void)
+{
unsigned long flags;
int need_wait = 0;
+ pr_debug("%s: start pid=%d\n",
+ __func__, current->pid);
spin_lock_irqsave(&dsi_mdp_lock, flags);
- status = MIPI_INP(MIPI_DSI_BASE + 0x0004);/* DSI_STATUS */
- if (status & 0x04) { /* MDP BUSY */
- INIT_COMPLETION(dsi_mdp_comp);
- need_wait = 1;
- pr_debug("%s: status=%x need_wait\n", __func__, (int)status);
- mipi_dsi_enable_irq(DSI_MDP_TERM);
- }
+ if (dsi_mdp_busy == TRUE)
+ need_wait++;
spin_unlock_irqrestore(&dsi_mdp_lock, flags);
- if (need_wait)
+ if (need_wait) {
+ /* wait until DMA finishes the current job */
+ pr_debug("%s: pending pid=%d\n",
+ __func__, current->pid);
wait_for_completion(&dsi_mdp_comp);
+ }
+ pr_debug("%s: done pid=%d\n",
+ __func__, current->pid);
}
/*
@@ -1589,27 +1580,52 @@
void mipi_dsi_cmdlist_commit(int from_mdp)
{
struct dcs_cmd_req *req;
+ int video;
+ u32 dsi_ctrl;
mutex_lock(&cmd_mutex);
req = mipi_dsi_cmdlist_get();
- if (req == NULL) {
- mutex_unlock(&cmd_mutex);
- return;
- }
+
+ /* make sure dsi_cmd_mdp is idle */
+ mipi_dsi_cmd_mdp_busy();
+
+ if (req == NULL)
+ goto need_lock;
+
+ video = MIPI_INP(MIPI_DSI_BASE + 0x0000);
+ video &= 0x02; /* VIDEO_MODE */
+
+ if (!video)
+ mipi_dsi_clk_cfg(1);
pr_debug("%s: from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid);
- if (!from_mdp) { /* from put */
- /* make sure dsi_cmd_mdp is idle */
- mipi_dsi_cmd_mdp_busy();
+ dsi_ctrl = MIPI_INP(MIPI_DSI_BASE + 0x0000);
+ if (dsi_ctrl & 0x02) {
+ /* video mode, make sure dsi_cmd_mdp is busy
+ * so dcs command will be txed at start of BLLP
+ */
+ mipi_dsi_wait_for_video_eng_busy();
+ } else {
+ /* command mode */
+ if (!from_mdp) { /* cmdlist_put */
+ /* make sure dsi_cmd_mdp is idle */
+ mipi_dsi_cmd_mdp_busy();
+ }
}
- mipi_dsi_clk_cfg(1);
if (req->flags & CMD_REQ_RX)
mipi_dsi_cmdlist_rx(req);
else
mipi_dsi_cmdlist_tx(req);
- mipi_dsi_clk_cfg(0);
+
+ if (!video)
+ mipi_dsi_clk_cfg(0);
+
+need_lock:
+
+ if (from_mdp) /* from pipe_commit */
+ mipi_dsi_cmd_mdp_start();
mutex_unlock(&cmd_mutex);
}
@@ -1762,8 +1778,8 @@
mipi_dsi_mdp_stat_inc(STAT_DSI_MDP);
spin_lock(&dsi_mdp_lock);
dsi_ctrl_lock = FALSE;
- mipi_dsi_disable_irq_nosync(DSI_MDP_TERM);
dsi_mdp_busy = FALSE;
+ mipi_dsi_disable_irq_nosync(DSI_MDP_TERM);
complete(&dsi_mdp_comp);
spin_unlock(&dsi_mdp_lock);
}
diff --git a/drivers/video/msm/mipi_novatek.c b/drivers/video/msm/mipi_novatek.c
index b893cc7..69ca0a3 100644
--- a/drivers/video/msm/mipi_novatek.c
+++ b/drivers/video/msm/mipi_novatek.c
@@ -302,19 +302,29 @@
static struct dsi_cmd_desc novatek_manufacture_id_cmd = {
DTYPE_DCS_READ, 1, 0, 1, 5, sizeof(manufacture_id), manufacture_id};
+static u32 manu_id;
+
+static void mipi_novatek_manufacture_cb(u32 data)
+{
+ manu_id = data;
+ pr_info("%s: manufacture_id=%x\n", __func__, manu_id);
+}
+
static uint32 mipi_novatek_manufacture_id(struct msm_fb_data_type *mfd)
{
- struct dsi_buf *rp, *tp;
- struct dsi_cmd_desc *cmd;
- uint32 *lp;
+ struct dcs_cmd_req cmdreq;
- tp = &novatek_tx_buf;
- rp = &novatek_rx_buf;
- cmd = &novatek_manufacture_id_cmd;
- mipi_dsi_cmds_rx(mfd, tp, rp, cmd, 3);
- lp = (uint32 *)rp->data;
- pr_info("%s: manufacture_id=%x\n", __func__, *lp);
- return *lp;
+ cmdreq.cmds = &novatek_manufacture_id_cmd;
+ cmdreq.cmds_cnt = 1;
+ cmdreq.flags = CMD_REQ_RX | CMD_REQ_COMMIT;
+ cmdreq.rlen = 3;
+ cmdreq.cb = mipi_novatek_manufacture_cb; /* call back */
+ mipi_dsi_cmdlist_put(&cmdreq);
+ /*
+ * blocked here, untill call back called
+ */
+
+ return manu_id;
}
static int fpga_addr;
@@ -380,6 +390,7 @@
struct msm_fb_data_type *mfd;
struct mipi_panel_info *mipi;
struct msm_panel_info *pinfo;
+ struct dcs_cmd_req cmdreq;
mfd = platform_get_drvdata(pdev);
if (!mfd)
@@ -394,23 +405,31 @@
mipi = &mfd->panel_info.mipi;
if (mipi->mode == DSI_VIDEO_MODE) {
- mipi_dsi_cmds_tx(&novatek_tx_buf, novatek_video_on_cmds,
- ARRAY_SIZE(novatek_video_on_cmds));
+ cmdreq.cmds = novatek_video_on_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(novatek_video_on_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
} else {
- mipi_dsi_cmds_tx(&novatek_tx_buf, novatek_cmd_on_cmds,
- ARRAY_SIZE(novatek_cmd_on_cmds));
+ cmdreq.cmds = novatek_cmd_on_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(novatek_cmd_on_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
/* clean up ack_err_status */
mipi_dsi_cmd_bta_sw_trigger();
mipi_novatek_manufacture_id(mfd);
}
-
return 0;
}
static int mipi_novatek_lcd_off(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
+ struct dcs_cmd_req cmdreq;
mfd = platform_get_drvdata(pdev);
@@ -419,8 +438,13 @@
if (mfd->key != MFD_KEY)
return -EINVAL;
- mipi_dsi_cmds_tx(&novatek_tx_buf, novatek_display_off_cmds,
- ARRAY_SIZE(novatek_display_off_cmds));
+ cmdreq.cmds = novatek_display_off_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(novatek_display_off_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+
+ mipi_dsi_cmdlist_put(&cmdreq);
return 0;
}
@@ -431,10 +455,10 @@
static struct dsi_cmd_desc backlight_cmd = {
DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(led_pwm1), led_pwm1};
-struct dcs_cmd_req cmdreq;
static void mipi_novatek_set_backlight(struct msm_fb_data_type *mfd)
{
+ struct dcs_cmd_req cmdreq;
if ((mipi_novatek_pdata->enable_wled_bl_ctrl)
&& (wled_trigger_initialized)) {
@@ -446,7 +470,7 @@
cmdreq.cmds = &backlight_cmd;
cmdreq.cmds_cnt = 1;
- cmdreq.flags = 0;
+ cmdreq.flags = CMD_REQ_COMMIT;
cmdreq.rlen = 0;
cmdreq.cb = NULL;
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index f74db80..e5516ab 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -129,7 +129,7 @@
INTERNAL_RSENSE = 0,
EXTERNAL_RSENSE,
ALT_LEAD_PAIR,
- GAIN_CALIBRATION_25MV,
+ GAIN_CALIBRATION_17P857MV,
OFFSET_CALIBRATION_SHORT_CADC_LEADS,
OFFSET_CALIBRATION_CSP_CSN,
OFFSET_CALIBRATION_CSP2_CSN2,
@@ -590,13 +590,31 @@
* @channel - Channel for which the historical offset and gain is
* calculated. Available channels are internal rsense,
* external rsense and alternate lead pairs.
- * @offset - Offset value for the channel.
- * @gain - Gain of the channel.
+ * @offset_raw - raw Offset value for the channel.
+ * @gain_raw - raw Gain of the channel.
+ * @ideal_offset_uv - ideal offset value for the channel.
+ * @ideal_gain_nv - ideal gain for the channel.
+ * @offset_uv - converted value of offset in uV.
+ * @gain_uv - converted value of gain in uV.
*/
struct qpnp_iadc_calib {
enum qpnp_iadc_channels channel;
- int32_t offset;
- int32_t gain;
+ uint16_t offset_raw;
+ uint16_t gain_raw;
+ uint32_t ideal_offset_uv;
+ uint32_t ideal_gain_nv;
+ uint32_t offset_uv;
+ uint32_t gain_uv;
+};
+
+/**
+ * struct qpnp_iadc_result - IADC read result structure.
+ * @oresult_uv - Result of ADC in uV.
+ * @result_ua - Result of ADC in uA.
+ */
+struct qpnp_iadc_result {
+ int32_t result_uv;
+ int32_t result_ua;
};
/**
@@ -854,7 +872,7 @@
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
{ return -ENXIO; }
-static inline int32_t qpnp_vadc_is_read(void)
+static inline int32_t qpnp_vadc_is_ready(void)
{ return -ENXIO; }
#endif
@@ -867,23 +885,18 @@
* @result: Current across rsens in mV.
*/
int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
- int32_t *result);
+ struct qpnp_iadc_result *result);
/**
- * qpnp_iadc_get_gain() - Performs gain calibration over 25mV reference
- * across CCADC.
- * @result: Gain result across 25mV reference.
+ * qpnp_iadc_get_gain_and_offset() - Performs gain calibration
+ * over 17.8571mV and offset over selected
+ * channel. Channel can be internal rsense,
+ * external rsense and alternate lead pair.
+ * @result: result structure where the gain and offset is stored of
+ * type qpnp_iadc_calib.
*/
-int32_t qpnp_iadc_get_gain(int32_t *result);
+int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_calib *result);
/**
- * qpnp_iadc_get_offset() - Performs offset calibration over selected
- * channel. Channel can be internal rsense,
- * external rsense and alternate lead pair.
- * @result: Gain result across 25mV reference.
- */
-int32_t qpnp_iadc_get_offset(enum qpnp_iadc_channels channel,
- int32_t *result);
-/**
* qpnp_iadc_is_ready() - Clients can use this API to check if the
* device is ready to use.
* @result: 0 on success and -EPROBE_DEFER when probe for the device
@@ -892,14 +905,12 @@
int32_t qpnp_iadc_is_ready(void);
#else
static inline int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
- int *result)
+ struct qpnp_iadc_result *result)
{ return -ENXIO; }
-static inline int32_t qpnp_iadc_get_gain(int32_t *result)
+static inline int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_calib
+ *result)
{ return -ENXIO; }
-static inline int32_t qpnp_iadc_get_offset(enum qpnp_iadc_channels channel,
- int32_t *result)
-{ return -ENXIO; }
-static inline int32_t qpnp_iadc_is_read(void)
+static inline int32_t qpnp_iadc_is_ready(void)
{ return -ENXIO; }
#endif
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index 34464c6..0fd11a3 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -69,4 +69,5 @@
struct v4l2_event_subscription *sub);
int msm_vidc_dqevent(void *instance, struct v4l2_event *event);
int msm_vidc_wait(void *instance);
+int msm_vidc_s_parm(void *instance, struct v4l2_streamparm *a);
#endif
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 1703c37..95df162 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -978,10 +978,15 @@
"ZERO", "SRC1", "SRC2", "IIR1", "IIR2"
};
-static const char * const rx_dsm_text[] = {
- "CIC_OUT", "DSM_INV"
+static const char * const rx_rdac5_text[] = {
+ "DEM4", "DEM3_INV"
};
+static const char * const rx_rdac7_text[] = {
+ "DEM6", "DEM5_INV"
+};
+
+
static const char * const sb_tx1_mux_text[] = {
"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
"DEC1"
@@ -1135,11 +1140,11 @@
static const struct soc_enum rx7_mix2_inp2_chain_enum =
SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX7_B3_CTL, 3, 5, rx_mix2_text);
-static const struct soc_enum rx4_dsm_enum =
- SOC_ENUM_SINGLE(TAIKO_A_CDC_RX4_B6_CTL, 4, 2, rx_dsm_text);
+static const struct soc_enum rx_rdac5_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_MISC, 2, 2, rx_rdac5_text);
-static const struct soc_enum rx6_dsm_enum =
- SOC_ENUM_SINGLE(TAIKO_A_CDC_RX6_B6_CTL, 4, 2, rx_dsm_text);
+static const struct soc_enum rx_rdac7_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_MISC, 1, 2, rx_rdac7_text);
static const struct soc_enum sb_tx1_mux_enum =
SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
@@ -1280,11 +1285,11 @@
static const struct snd_kcontrol_new rx7_mix2_inp2_mux =
SOC_DAPM_ENUM("RX7 MIX2 INP2 Mux", rx7_mix2_inp2_chain_enum);
-static const struct snd_kcontrol_new rx4_dsm_mux =
- SOC_DAPM_ENUM("RX4 DSM MUX Mux", rx4_dsm_enum);
+static const struct snd_kcontrol_new rx_dac5_mux =
+ SOC_DAPM_ENUM("RDAC5 MUX Mux", rx_rdac5_enum);
-static const struct snd_kcontrol_new rx6_dsm_mux =
- SOC_DAPM_ENUM("RX6 DSM MUX Mux", rx6_dsm_enum);
+static const struct snd_kcontrol_new rx_dac7_mux =
+ SOC_DAPM_ENUM("RDAC7 MUX Mux", rx_rdac7_enum);
static const struct snd_kcontrol_new sb_tx1_mux =
SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
@@ -2635,15 +2640,18 @@
{"LINEOUT1 DAC", NULL, "RX3 MIX1"},
- {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
- {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
- {"LINEOUT3 DAC", NULL, "RX4 DSM MUX"},
+
+ {"RDAC5 MUX", "DEM3_INV", "RX3 MIX1"},
+ {"RDAC5 MUX", "DEM4", "RX4 MIX1"},
+
+ {"LINEOUT3 DAC", NULL, "RDAC5 MUX"},
{"LINEOUT2 DAC", NULL, "RX5 MIX1"},
- {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
- {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
- {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
+ {"RDAC7 MUX", "DEM5_INV", "RX5 MIX1"},
+ {"RDAC7 MUX", "DEM6", "RX6 MIX1"},
+
+ {"LINEOUT4 DAC", NULL, "RDAC7 MUX"},
{"SPK PA", NULL, "SPK DAC"},
{"SPK DAC", NULL, "RX7 MIX2"},
@@ -3844,13 +3852,6 @@
0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU),
- SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TAIKO_A_CDC_CLK_RX_B1_CTL, 3, 0,
- &rx4_dsm_mux, taiko_codec_enable_interpolator,
- SND_SOC_DAPM_PRE_PMU),
-
- SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TAIKO_A_CDC_CLK_RX_B1_CTL, 5, 0,
- &rx6_dsm_mux, taiko_codec_enable_interpolator,
- SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_MIXER("RX1 CHAIN", TAIKO_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
SND_SOC_DAPM_MIXER("RX2 CHAIN", TAIKO_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
@@ -3898,6 +3899,11 @@
SND_SOC_DAPM_MUX("RX7 MIX2 INP2", SND_SOC_NOPM, 0, 0,
&rx7_mix2_inp2_mux),
+ SND_SOC_DAPM_MUX("RDAC5 MUX", SND_SOC_NOPM, 0, 0,
+ &rx_dac5_mux),
+ SND_SOC_DAPM_MUX("RDAC7 MUX", SND_SOC_NOPM, 0, 0,
+ &rx_dac7_mux),
+
SND_SOC_DAPM_SUPPLY("CLASS_H_CLK", TAIKO_A_CDC_CLK_OTHR_CTL, 0, 0,
taiko_codec_enable_class_h_clk, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_PRE_PMD),
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index 69256363..016ef94 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -845,6 +845,21 @@
return 0;
}
+static int mpq8064_proxy_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ pr_debug("%s ()\n", __func__);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ return 0;
+}
+
static int msm_be_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -1570,6 +1585,7 @@
.codec_dai_name = "msm-stub-rx",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+ .be_hw_params_fixup = mpq8064_proxy_be_params_fixup,
.ignore_pmdown_time = 1, /* this dainlink has playback support */
},
{
@@ -1580,6 +1596,7 @@
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-tx",
.no_pcm = 1,
+ .be_hw_params_fixup = mpq8064_proxy_be_params_fixup,
.be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
},
/* AUX PCM Backend DAI Links */
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index dc851ce..915c3c2 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1496,9 +1496,6 @@
struct snd_soc_dpcm_params *dpcm_params;
int ret = 0;
- if ((cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) ||
- (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH))
- return ret;
list_for_each_entry(dpcm_params, &fe->dpcm[stream].be_clients, list_be) {
@@ -1767,6 +1764,7 @@
if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
continue;