Merge "ASoC: msm: qdsp6v2: add support for device mute"
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
index d0cad52..9acf54a 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
@@ -33,6 +33,9 @@
apply the default RSENSE if conditions are met.
1 : Select this type to read the IADC, SMBB trim register and
manufacturer type and apply the default RSENSE if conditions are met.
+- qcom,pmic-revid : Phandle pointing to the revision peripheral node. Use it to query the
+ PMIC type and revision for applying the appropriate temperature
+ compensation parameters.
Channel node
NOTE: Atleast one Channel node is required.
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
index dd0c440..83403ba 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
@@ -22,6 +22,9 @@
Optional properties:
- qcom,vadc-poll-eoc: Use polling instead of interrupts for End of Conversion completion.
+- qcom,pmic-revid : Phandle pointing to the revision peripheral node. Use it to query the
+ PMIC type and revision for applying the appropriate temperature
+ compensation parameters.
Client required property:
- qcom,<consumer name>-vadc : The phandle to the corresponding vadc device.
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
index e98ee05..32f6a24 100644
--- a/Documentation/devicetree/bindings/memory.txt
+++ b/Documentation/devicetree/bindings/memory.txt
@@ -36,6 +36,7 @@
reg = <(baseaddr) (size)>;
(linux,contiguous-region);
(linux,default-contiguous-region);
+ (linux,memory-limit);
label = (unique_name);
};
@@ -48,6 +49,11 @@
linux,default-contiguous-region: property indicating that the region
is the default region for all contiguous memory
allocations, Linux specific (optional)
+linux,memory-limit: property specifying an upper bound on the physical address
+ of the region if the region is placed dynamically. If no limit
+ is specificed, the region may be placed anywhere in the physical
+ address space. 0 may be used to specify lowmem (i.e. the region
+ will be placed in the direct mapped lowmem region)
label: an internal name used for automatically associating the
cma region with a given device. The label is optional;
if the label is not given the client is responsible for
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index d502f78..8c41926 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -55,6 +55,9 @@
no default value that the driver assumes if this property
is not specified. So if this property is not specified,
then SDHC driver will not vote for PM QOS.
+ - qcom,dat1-mpm-int: specifies MPM interrupt number (e.g. sdhc_2 node below)
+ corresponding to DAT1 line of SDHC (used only if slot has dedicated
+ DAT1 MSM pin (not GPIO))
In the following, <supply> can be vdd (flash core voltage) or vdd-io (I/O voltage).
- qcom,<supply>-always-on - specifies whether supply should be kept "on" always.
@@ -165,4 +168,5 @@
<81 512 106496 212992>, /* 208 MB/s */
<81 512 2147483647 4294967295>; /* Max. bandwidth */
qcom,bus-bw-vectors-bps = <0 13631488 27262976 54525952 109051904 218103808 4294967295>;
+ qcom,dat1-mpm-int = <44>;
};
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 9adbf81..7a60861 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -22,7 +22,7 @@
#address-cells = <1>;
#size-cells = <1>;
- qcom,revid@100 {
+ pm8110_revid: qcom,revid@100 {
compatible = "qcom,qpnp-revid";
reg = <0x100 0x100>;
};
@@ -219,6 +219,7 @@
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
qcom,vadc-poll-eoc;
+ qcom,pmic-revid = <&pm8110_revid>;
chan@8 {
label = "die_temp";
@@ -268,6 +269,7 @@
qcom,iadc-vadc = <&pm8110_vadc>;
qcom,iadc-poll-eoc;
qcom,use-default-rds-trim = <1>;
+ qcom,pmic-revid = <&pm8110_revid>;
chan@0 {
label = "internal_rsense";
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 41897da..08d3d05 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -364,6 +364,7 @@
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
qcom,vadc-poll-eoc;
+ qcom,pmic-revid = <&pm8226_revid>;
chan@8 {
label = "die_temp";
@@ -424,6 +425,7 @@
qcom,iadc-vadc = <&pm8226_vadc>;
qcom,iadc-poll-eoc;
qcom,use-default-rds-trim = <0>;
+ qcom,pmic-revid = <&pm8226_revid>;
chan@0 {
label = "internal_rsense";
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 94a4e83..a0e02f7 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -27,7 +27,7 @@
reg = <0x900 0x100>;
};
- qcom,revid@100 {
+ pm8941_revid: qcom,revid@100 {
compatible = "qcom,qpnp-revid";
reg = <0x100 0x100>;
};
@@ -577,6 +577,7 @@
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
qcom,vadc-poll-eoc;
+ qcom,pmic-revid = <&pm8941_revid>;
chan@0 {
label = "usb_in";
@@ -824,6 +825,7 @@
qcom,iadc-vadc = <&pm8941_vadc>;
qcom,iadc-poll-eoc;
qcom,use-default-rds-trim = <0>;
+ qcom,pmic-revid = <&pm8941_revid>;
chan@0 {
label = "internal_rsense";
diff --git a/arch/arm/boot/dts/msm8226-bus.dtsi b/arch/arm/boot/dts/msm8226-bus.dtsi
index 74b4a30..a2f91cf 100644
--- a/arch/arm/boot/dts/msm8226-bus.dtsi
+++ b/arch/arm/boot/dts/msm8226-bus.dtsi
@@ -998,7 +998,7 @@
qcom,fabclk-dual = "mem_clk";
qcom,fabclk-active = "mem_a_clk";
qcom,ntieredslaves = <0>;
- qcom,qos-freq = <4800>;
+ qcom,qos-freq = <19200>;
qcom,hw-sel = "BIMC";
qcom,rpm-en;
@@ -1008,12 +1008,18 @@
qcom,masterp = <0>;
qcom,tier = <2>;
qcom,hw-sel = "BIMC";
- qcom,mode = "Fixed";
+ qcom,mode = "Limiter";
qcom,qport = <0>;
qcom,ws = <10000>;
qcom,mas-hw-id = <0>;
qcom,prio-rd = <0>;
qcom,prio-wr = <0>;
+ qcom,mode-thresh = "Fixed";
+ qcom,thresh = <1800000>;
+ qcom,dual-conf;
+ qcom,bimc,bw = <450000>;
+ qcom,bimc,gp = <5000>;
+ qcom,bimc,thmp = <50>;
};
mas-mss-proc {
diff --git a/arch/arm/boot/dts/msm8926.dtsi b/arch/arm/boot/dts/msm8926.dtsi
index e866286..394f4a9 100644
--- a/arch/arm/boot/dts/msm8926.dtsi
+++ b/arch/arm/boot/dts/msm8926.dtsi
@@ -22,6 +22,11 @@
/ {
model = "Qualcomm MSM 8926";
compatible = "qcom,msm8926";
+
+};
+
+&qsecom_mem {
+ linux,memory-limit = <0x0>;
};
&soc {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index da5474d..a3b3c87 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -509,6 +509,7 @@
<78 512 800000 1600000>, /* 200 MB/s */
<78 512 2048000 4096000>; /* Max. bandwidth */
qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 100000000 200000000 4294967295>;
+ qcom,dat1-mpm-int = <42>;
status = "disable";
};
@@ -535,6 +536,7 @@
<81 512 800000 1600000>, /* 200 MB/s */
<81 512 2048000 4096000>; /* Max. bandwidth */
qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 100000000 200000000 4294967295>;
+ qcom,dat1-mpm-int = <44>;
status = "disable";
};
@@ -542,8 +544,17 @@
compatible = "qcom,sdhci-msm";
reg = <0xf9864900 0x11c>, <0xf9864000 0x800>;
reg-names = "hc_mem", "core_mem";
- interrupts = <0 127 0>, <0 224 0>;
- interrupt-names = "hc_irq", "pwr_irq";
+
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_3>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 127 0
+ 1 &intc 0 224 0
+ 2 &msmgpio 37 0x8>;
+ interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq";
+
gpios = <&msmgpio 40 0>, /* CLK */
<&msmgpio 39 0>, /* CMD */
<&msmgpio 38 0>, /* DATA0 */
@@ -575,8 +586,17 @@
compatible = "qcom,sdhci-msm";
reg = <0xf98e4900 0x11c>, <0xf98e4000 0x800>;
reg-names = "hc_mem", "core_mem";
- interrupts = <0 129 0>, <0 227 0>;
- interrupt-names = "hc_irq", "pwr_irq";
+
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_4>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 129 0
+ 1 &intc 0 227 0
+ 2 &msmgpio 95 0x8>;
+ interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq";
+
gpios = <&msmgpio 93 0>, /* CLK */
<&msmgpio 91 0>, /* CMD */
<&msmgpio 96 0>, /* DATA0 */
diff --git a/arch/arm/mach-msm/mpm-of.c b/arch/arm/mach-msm/mpm-of.c
index dc3af3e..f1bf64f 100644
--- a/arch/arm/mach-msm/mpm-of.c
+++ b/arch/arm/mach-msm/mpm-of.c
@@ -531,6 +531,7 @@
void msm_mpm_exit_sleep(bool from_idle)
{
unsigned long pending;
+ uint32_t *enabled_intr;
int i;
int k;
@@ -539,12 +540,16 @@
return;
}
+ enabled_intr = from_idle ? msm_mpm_enabled_irq :
+ msm_mpm_wake_irq;
+
for (i = 0; i < MSM_MPM_REG_WIDTH; i++) {
pending = msm_mpm_read(MSM_MPM_REG_STATUS, i);
+ pending &= enabled_intr[i];
if (MSM_MPM_DEBUG_PENDING_IRQ & msm_mpm_debug_mask)
- pr_info("%s: pending.%d: 0x%08lx", __func__,
- i, pending);
+ pr_info("%s: enabled_intr pending.%d: 0x%08x 0x%08lx\n",
+ __func__, i, enabled_intr[i], pending);
k = find_first_bit(&pending, 32);
while (k < 32) {
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 606383a..adac211 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -212,6 +212,7 @@
unsigned long len;
__be32 *prop;
char *name;
+ phys_addr_t limit = MEMBLOCK_ALLOC_ANYWHERE;
if (!of_get_flat_dt_prop(node, "linux,contiguous-region", NULL))
return 0;
@@ -225,9 +226,13 @@
name = of_get_flat_dt_prop(node, "label", NULL);
- pr_info("Found %s, memory base %lx, size %ld MiB\n", uname,
- (unsigned long)base, (unsigned long)size / SZ_1M);
- dma_contiguous_reserve_area(size, &base, MEMBLOCK_ALLOC_ANYWHERE, name);
+ prop = of_get_flat_dt_prop(node, "linux,memory-limit", NULL);
+ if (prop)
+ limit = be32_to_cpu(prop[0]);
+
+ pr_info("Found %s, memory base %lx, size %ld MiB, limit %pa\n", uname,
+ (unsigned long)base, (unsigned long)size / SZ_1M, &limit);
+ dma_contiguous_reserve_area(size, &base, limit, name);
return 0;
}
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index 7bc8773..37a11d2 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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,6 +986,92 @@
}
EXPORT_SYMBOL(qpnp_vadc_check_result);
+int qpnp_adc_get_revid_version(struct device *dev)
+{
+ struct pmic_revid_data *revid_data;
+ struct device_node *revid_dev_node;
+
+ revid_dev_node = of_parse_phandle(dev->of_node,
+ "qcom,pmic-revid", 0);
+ if (!revid_dev_node) {
+ pr_debug("Missing qcom,pmic-revid property\n");
+ return -EINVAL;
+ }
+
+ revid_data = get_revid_data(revid_dev_node);
+ if (IS_ERR(revid_data)) {
+ pr_debug("revid error rc = %ld\n", PTR_ERR(revid_data));
+ return -EINVAL;
+ }
+
+ if ((revid_data->rev1 == PM8941_V3P1_REV1) &&
+ (revid_data->rev2 == PM8941_V3P1_REV2) &&
+ (revid_data->rev3 == PM8941_V3P1_REV3) &&
+ (revid_data->rev4 == PM8941_V3P1_REV4) &&
+ (revid_data->pmic_type == PM8941_V3P1_TYPE) &&
+ (revid_data->pmic_subtype == PM8941_V3P1_SUBTYPE))
+ return QPNP_REV_ID_8941_3_1;
+ else if ((revid_data->rev1 == PM8941_V3P0_REV1) &&
+ (revid_data->rev2 == PM8941_V3P0_REV2) &&
+ (revid_data->rev3 == PM8941_V3P0_REV3) &&
+ (revid_data->rev4 == PM8941_V3P0_REV4) &&
+ (revid_data->pmic_type == PM8941_V3P0_TYPE) &&
+ (revid_data->pmic_subtype == PM8941_V3P0_SUBTYPE))
+ return QPNP_REV_ID_8941_3_0;
+ else if ((revid_data->rev1 == PM8941_V2P0_REV1) &&
+ (revid_data->rev2 == PM8941_V2P0_REV2) &&
+ (revid_data->rev3 == PM8941_V2P0_REV3) &&
+ (revid_data->rev4 == PM8941_V2P0_REV4) &&
+ (revid_data->pmic_type == PM8941_V2P0_TYPE) &&
+ (revid_data->pmic_subtype == PM8941_V2P0_SUBTYPE))
+ return QPNP_REV_ID_8941_2_0;
+ else if ((revid_data->rev1 == PM8226_V2P2_REV1) &&
+ (revid_data->rev2 == PM8226_V2P2_REV2) &&
+ (revid_data->rev3 == PM8226_V2P2_REV3) &&
+ (revid_data->rev4 == PM8226_V2P2_REV4) &&
+ (revid_data->pmic_type == PM8226_V2P2_TYPE) &&
+ (revid_data->pmic_subtype == PM8226_V2P2_SUBTYPE))
+ return QPNP_REV_ID_8026_2_2;
+ else if ((revid_data->rev1 == PM8226_V2P1_REV1) &&
+ (revid_data->rev2 == PM8226_V2P1_REV2) &&
+ (revid_data->rev3 == PM8226_V2P1_REV3) &&
+ (revid_data->rev4 == PM8226_V2P1_REV4) &&
+ (revid_data->pmic_type == PM8226_V2P1_TYPE) &&
+ (revid_data->pmic_subtype == PM8226_V2P1_SUBTYPE))
+ return QPNP_REV_ID_8026_2_1;
+ else if ((revid_data->rev1 == PM8226_V2P0_REV1) &&
+ (revid_data->rev2 == PM8226_V2P0_REV2) &&
+ (revid_data->rev3 == PM8226_V2P0_REV3) &&
+ (revid_data->rev4 == PM8226_V2P0_REV4) &&
+ (revid_data->pmic_type == PM8226_V2P0_TYPE) &&
+ (revid_data->pmic_subtype == PM8226_V2P0_SUBTYPE))
+ return QPNP_REV_ID_8026_2_0;
+ else if ((revid_data->rev1 == PM8226_V1P0_REV1) &&
+ (revid_data->rev2 == PM8226_V1P0_REV2) &&
+ (revid_data->rev3 == PM8226_V1P0_REV3) &&
+ (revid_data->rev4 == PM8226_V1P0_REV4) &&
+ (revid_data->pmic_type == PM8226_V1P0_TYPE) &&
+ (revid_data->pmic_subtype == PM8226_V1P0_SUBTYPE))
+ return QPNP_REV_ID_8026_1_0;
+ else if ((revid_data->rev1 == PM8110_V1P0_REV1) &&
+ (revid_data->rev2 == PM8110_V1P0_REV2) &&
+ (revid_data->rev3 == PM8110_V1P0_REV3) &&
+ (revid_data->rev4 == PM8110_V1P0_REV4) &&
+ (revid_data->pmic_type == PM8110_V1P0_TYPE) &&
+ (revid_data->pmic_subtype == PM8110_V1P0_SUBTYPE))
+ return QPNP_REV_ID_8110_1_0;
+ else if ((revid_data->rev1 == PM8110_V2P0_REV1) &&
+ (revid_data->rev2 == PM8110_V2P0_REV2) &&
+ (revid_data->rev3 == PM8110_V2P0_REV3) &&
+ (revid_data->rev4 == PM8110_V2P0_REV4) &&
+ (revid_data->pmic_type == PM8110_V2P0_TYPE) &&
+ (revid_data->pmic_subtype == PM8110_V2P0_SUBTYPE))
+ return QPNP_REV_ID_8110_2_0;
+ else
+ return -EINVAL;
+}
+EXPORT_SYMBOL(qpnp_adc_get_revid_version);
+
int32_t qpnp_adc_get_devicetree_data(struct spmi_device *spmi,
struct qpnp_adc_drv *adc_qpnp)
{
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 44da261..ec6d8ec 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -340,48 +340,8 @@
return 0;
}
-#define QPNP_IADC_PM8941_3_1_REV2 3
-#define QPNP_IADC_PM8941_3_1_REV3 2
-#define QPNP_IADC_PM8026_1_REV2 1
-#define QPNP_IADC_PM8026_1_REV3 2
-#define QPNP_IADC_PM8026_2_REV2 4
-#define QPNP_IADC_PM8026_2_REV3 2
-#define QPNP_IADC_PM8110_1_REV2 2
-#define QPNP_IADC_PM8110_1_REV3 2
-
-#define QPNP_IADC_REV_ID_8941_3_1 1
-#define QPNP_IADC_REV_ID_8026_1_0 2
-#define QPNP_IADC_REV_ID_8026_2_0 3
-#define QPNP_IADC_REV_ID_8110_1_0 4
-
-static void qpnp_temp_comp_version_check(struct qpnp_iadc_chip *iadc,
- int32_t *version)
-{
- if ((iadc->iadc_comp.revision_dig_major ==
- QPNP_IADC_PM8941_3_1_REV2) &&
- (iadc->iadc_comp.revision_ana_minor ==
- QPNP_IADC_PM8941_3_1_REV3))
- *version = QPNP_IADC_REV_ID_8941_3_1;
- else if ((iadc->iadc_comp.revision_dig_major ==
- QPNP_IADC_PM8026_1_REV2) &&
- (iadc->iadc_comp.revision_ana_minor ==
- QPNP_IADC_PM8026_1_REV3))
- *version = QPNP_IADC_REV_ID_8026_1_0;
- else if ((iadc->iadc_comp.revision_dig_major ==
- QPNP_IADC_PM8026_2_REV2) &&
- (iadc->iadc_comp.revision_ana_minor ==
- QPNP_IADC_PM8026_2_REV3))
- *version = QPNP_IADC_REV_ID_8026_2_0;
- else if ((iadc->iadc_comp.revision_dig_major ==
- QPNP_IADC_PM8110_1_REV2) &&
- (iadc->iadc_comp.revision_ana_minor ==
- QPNP_IADC_PM8110_1_REV3))
- *version = QPNP_IADC_REV_ID_8110_1_0;
- else
- *version = -EINVAL;
-
- return;
-}
+#define QPNP_IADC_PM8026_2_REV2 4
+#define QPNP_IADC_PM8026_2_REV3 2
#define QPNP_COEFF_1 969000
#define QPNP_COEFF_2 32
@@ -408,15 +368,19 @@
#define QPNP_COEFF_22 5000000
#define QPNP_COEFF_23 3722500
#define QPNP_COEFF_24 84
+#define QPNP_COEFF_25 33
+#define QPNP_COEFF_26 22
+#define QPNP_COEFF_27 53
+#define QPNP_COEFF_28 48
static int32_t qpnp_iadc_comp(int64_t *result, struct qpnp_iadc_chip *iadc,
int64_t die_temp)
{
int64_t temp_var = 0, sys_gain_coeff = 0, old;
int32_t coeff_a = 0, coeff_b = 0;
- int32_t version;
+ int version = 0;
- qpnp_temp_comp_version_check(iadc, &version);
+ version = qpnp_adc_get_revid_version(iadc->dev);
if (version == -EINVAL)
return 0;
@@ -431,7 +395,7 @@
iadc->iadc_comp.sys_gain;
switch (version) {
- case QPNP_IADC_REV_ID_8941_3_1:
+ case QPNP_REV_ID_8941_3_1:
switch (iadc->iadc_comp.id) {
case COMP_ID_GF:
if (!iadc->iadc_comp.ext_rsense) {
@@ -470,7 +434,60 @@
break;
}
break;
- case QPNP_IADC_REV_ID_8026_1_0:
+ case QPNP_REV_ID_8026_2_1:
+ case QPNP_REV_ID_8026_2_2:
+ /* pm8026 rev 2.1 and 2.2 */
+ switch (iadc->iadc_comp.id) {
+ case COMP_ID_GF:
+ if (!iadc->iadc_comp.ext_rsense) {
+ /* internal rsense */
+ if (*result < 0) {
+ /* charge */
+ coeff_a = 0;
+ coeff_b = 0;
+ } else {
+ coeff_a = QPNP_COEFF_25;
+ coeff_b = 0;
+ }
+ } else {
+ if (*result < 0) {
+ /* charge */
+ coeff_a = 0;
+ coeff_b = 0;
+ } else {
+ /* discharge */
+ coeff_a = 0;
+ coeff_b = 0;
+ }
+ }
+ break;
+ case COMP_ID_TSMC:
+ default:
+ if (!iadc->iadc_comp.ext_rsense) {
+ /* internal rsense */
+ if (*result < 0) {
+ /* charge */
+ coeff_a = 0;
+ coeff_b = 0;
+ } else {
+ coeff_a = QPNP_COEFF_26;
+ coeff_b = 0;
+ }
+ } else {
+ if (*result < 0) {
+ /* charge */
+ coeff_a = 0;
+ coeff_b = 0;
+ } else {
+ /* discharge */
+ coeff_a = 0;
+ coeff_b = 0;
+ }
+ }
+ break;
+ }
+ break;
+ case QPNP_REV_ID_8026_1_0:
/* pm8026 rev 1.0 */
switch (iadc->iadc_comp.id) {
case COMP_ID_GF:
@@ -522,7 +539,7 @@
break;
}
break;
- case QPNP_IADC_REV_ID_8110_1_0:
+ case QPNP_REV_ID_8110_1_0:
/* pm8110 rev 1.0 */
switch (iadc->iadc_comp.id) {
case COMP_ID_GF:
@@ -554,8 +571,41 @@
break;
}
break;
+ case QPNP_REV_ID_8110_2_0:
+ die_temp -= 25000;
+ /* pm8110 rev 2.0 */
+ switch (iadc->iadc_comp.id) {
+ case COMP_ID_GF:
+ if (!iadc->iadc_comp.ext_rsense) {
+ /* internal rsense */
+ if (*result < 0) {
+ /* charge */
+ coeff_a = 0;
+ coeff_b = 0;
+ } else {
+ coeff_a = QPNP_COEFF_27;
+ coeff_b = 0;
+ }
+ }
+ break;
+ case COMP_ID_SMIC:
+ default:
+ if (!iadc->iadc_comp.ext_rsense) {
+ /* internal rsense */
+ if (*result < 0) {
+ /* charge */
+ coeff_a = 0;
+ coeff_b = 0;
+ } else {
+ coeff_a = QPNP_COEFF_28;
+ coeff_b = 0;
+ }
+ }
+ break;
+ }
+ break;
default:
- case QPNP_IADC_REV_ID_8026_2_0:
+ case QPNP_REV_ID_8026_2_0:
/* pm8026 rev 1.0 */
coeff_a = 0;
coeff_b = 0;
@@ -578,7 +628,8 @@
temp_var = div64_s64(temp_var * sys_gain_coeff, 1000000);
*result = div64_s64(*result * 1000, temp_var);
}
- pr_debug("%lld compensated into %lld\n", old, *result);
+ pr_debug("%lld compensated into %lld, a: %d, b: %d, sys_gain: %lld\n",
+ old, *result, coeff_a, coeff_b, sys_gain_coeff);
return 0;
}
@@ -844,9 +895,10 @@
bool batfet_closed)
{
uint8_t rslt_lsb, rslt_msb;
- int32_t rc = 0;
+ int32_t rc = 0, version = 0;
uint16_t raw_data;
uint32_t mode_sel = 0;
+ bool iadc_offset_ch_batfet_check;
if (qpnp_iadc_is_valid(iadc) < 0)
return -EPROBE_DEFER;
@@ -868,13 +920,22 @@
iadc->adc->calib.gain_raw = raw_data;
/*
- * there is a features in the BMS where if the batfet is opened
- * the BMS reads from INTERNAL_RSENSE (channel 0) actually go to
+ * there is a features on PM8941 in the BMS where if the batfet is
+ * opened the BMS reads from INTERNAL_RSENSE (channel 0) actually go to
* OFFSET_CALIBRATION_CSP_CSN (channel 5). Hence if batfet is opened
* we have to calibrate based on OFFSET_CALIBRATION_CSP_CSN even for
* internal rsense.
*/
- if (!batfet_closed || iadc->external_rsense) {
+ version = qpnp_adc_get_revid_version(iadc->dev);
+ if ((version == QPNP_REV_ID_8941_3_1) ||
+ (version == QPNP_REV_ID_8941_3_0) ||
+ (version == QPNP_REV_ID_8941_2_0))
+ iadc_offset_ch_batfet_check = true;
+ else
+ iadc_offset_ch_batfet_check = false;
+
+ if ((iadc_offset_ch_batfet_check && !batfet_closed) ||
+ (iadc->external_rsense)) {
/* external offset calculation */
rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP_CSN,
&raw_data, mode_sel);
@@ -1141,10 +1202,12 @@
result->result_uv = -result->result_uv;
result_current = -result_current;
}
+ result_current *= -1;
rc = qpnp_iadc_comp_result(iadc, &result_current);
if (rc < 0)
pr_err("Error during compensating the IADC\n");
rc = 0;
+ result_current *= -1;
result->result_ua = (int32_t) result_current;
fail:
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index d462fb3..346a72d 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -512,63 +512,52 @@
#define QPNP_VBAT_COEFF_13 102640000
#define QPNP_VBAT_COEFF_14 22220000
#define QPNP_VBAT_COEFF_15 83060000
-
-#define QPNP_VADC_REV_ID_8941_3_1 1
-#define QPNP_VADC_REV_ID_8026_1_0 2
-#define QPNP_VADC_REV_ID_8026_2_0 3
-
-static void qpnp_temp_comp_version_check(struct qpnp_vadc_chip *vadc,
- int32_t *version)
-{
- if (vadc->revision_dig_major == 3 &&
- vadc->revision_ana_minor == 2)
- *version = QPNP_VADC_REV_ID_8941_3_1;
- else if (vadc->revision_dig_major == 1 &&
- vadc->revision_ana_minor == 2)
- *version = QPNP_VADC_REV_ID_8026_1_0;
- else if (vadc->revision_dig_major == 2 &&
- vadc->revision_ana_minor == 2)
- *version = QPNP_VADC_REV_ID_8026_2_0;
- else
- *version = -EINVAL;
-
- return;
-}
+#define QPNP_VBAT_COEFF_16 2810
+#define QPNP_VBAT_COEFF_17 5260
+#define QPNP_VBAT_COEFF_18 8027
+#define QPNP_VBAT_COEFF_19 2347
+#define QPNP_VBAT_COEFF_20 6043
+#define QPNP_VBAT_COEFF_21 1914
+#define QPNP_VBAT_OFFSET_SMIC 9446
+#define QPNP_VBAT_OFFSET_GF 9441
+#define QPNP_OCV_OFFSET_SMIC 4596
+#define QPNP_OCV_OFFSET_GF 5896
+#define QPNP_VBAT_COEFF_22 6800
+#define QPNP_VBAT_COEFF_23 3500
+#define QPNP_VBAT_COEFF_24 4360
+#define QPNP_VBAT_COEFF_25 8060
static int32_t qpnp_ocv_comp(int64_t *result,
struct qpnp_vadc_chip *vadc, int64_t die_temp)
{
int64_t temp_var = 0;
int64_t old = *result;
- int32_t version;
+ int version;
- qpnp_temp_comp_version_check(vadc, &version);
+ version = qpnp_adc_get_revid_version(vadc->dev);
if (version == -EINVAL)
return 0;
- if (die_temp < 25000)
- return 0;
-
- if (die_temp > 60000)
- die_temp = 60000;
+ if (version == QPNP_REV_ID_8026_2_2) {
+ if (die_temp > 25000)
+ return 0;
+ }
switch (version) {
- case QPNP_VADC_REV_ID_8941_3_1:
+ case QPNP_REV_ID_8941_3_1:
switch (vadc->id) {
case COMP_ID_TSMC:
- temp_var = (((die_temp *
- (-QPNP_VBAT_COEFF_4))
- + QPNP_VBAT_COEFF_5));
+ temp_var = ((die_temp - 25000) *
+ (-QPNP_VBAT_COEFF_4));
break;
default:
case COMP_ID_GF:
- temp_var = (((die_temp *
- (-QPNP_VBAT_COEFF_1))
- + QPNP_VBAT_COEFF_2));
+ temp_var = ((die_temp - 25000) *
+ (-QPNP_VBAT_COEFF_1));
break;
}
break;
- case QPNP_VADC_REV_ID_8026_1_0:
+ case QPNP_REV_ID_8026_1_0:
switch (vadc->id) {
case COMP_ID_TSMC:
temp_var = (((die_temp *
@@ -583,19 +572,55 @@
break;
}
break;
- case QPNP_VADC_REV_ID_8026_2_0:
+ case QPNP_REV_ID_8026_2_0:
+ case QPNP_REV_ID_8026_2_1:
switch (vadc->id) {
case COMP_ID_TSMC:
- temp_var = ((die_temp - 2500) *
+ temp_var = ((die_temp - 25000) *
(-QPNP_VBAT_COEFF_10));
break;
default:
case COMP_ID_GF:
- temp_var = ((die_temp - 2500) *
+ temp_var = ((die_temp - 25000) *
(-QPNP_VBAT_COEFF_8));
break;
}
break;
+ case QPNP_REV_ID_8026_2_2:
+ switch (vadc->id) {
+ case COMP_ID_TSMC:
+ *result -= QPNP_VBAT_COEFF_22;
+ temp_var = (die_temp - 25000) *
+ QPNP_VBAT_COEFF_24;
+ break;
+ default:
+ case COMP_ID_GF:
+ *result -= QPNP_VBAT_COEFF_22;
+ temp_var = (die_temp - 25000) *
+ QPNP_VBAT_COEFF_25;
+ break;
+ }
+ case QPNP_REV_ID_8110_2_0:
+ switch (vadc->id) {
+ case COMP_ID_SMIC:
+ *result -= QPNP_OCV_OFFSET_SMIC;
+ if (die_temp < 25000)
+ temp_var = QPNP_VBAT_COEFF_18;
+ else
+ temp_var = QPNP_VBAT_COEFF_19;
+ temp_var = (die_temp - 25000) * temp_var;
+ break;
+ default:
+ case COMP_ID_GF:
+ *result -= QPNP_OCV_OFFSET_GF;
+ if (die_temp < 25000)
+ temp_var = QPNP_VBAT_COEFF_20;
+ else
+ temp_var = QPNP_VBAT_COEFF_21;
+ temp_var = (die_temp - 25000) * temp_var;
+ break;
+ }
+ break;
default:
temp_var = 0;
break;
@@ -618,35 +643,36 @@
{
int64_t temp_var = 0;
int64_t old = *result;
- int32_t version;
+ int version;
- qpnp_temp_comp_version_check(vadc, &version);
+ version = qpnp_adc_get_revid_version(vadc->dev);
if (version == -EINVAL)
return 0;
- if (die_temp < 25000)
- return 0;
-
- /* min(die_temp_c, 60_degC) */
- if (die_temp > 60000)
- die_temp = 60000;
+ if (version != QPNP_REV_ID_8941_3_1) {
+ /* min(die_temp_c, 60_degC) */
+ if (die_temp > 60000)
+ die_temp = 60000;
+ }
switch (version) {
- case QPNP_VADC_REV_ID_8941_3_1:
+ case QPNP_REV_ID_8941_3_1:
switch (vadc->id) {
case COMP_ID_TSMC:
- temp_var = (die_temp *
+ temp_var = ((die_temp - 25000) *
(-QPNP_VBAT_COEFF_1));
break;
default:
case COMP_ID_GF:
- temp_var = (((die_temp *
- (-QPNP_VBAT_COEFF_6))
- + QPNP_VBAT_COEFF_7));
+ /* min(die_temp_c, 60_degC) */
+ if (die_temp > 60000)
+ die_temp = 60000;
+ temp_var = ((die_temp - 25000) *
+ (-QPNP_VBAT_COEFF_1));
break;
}
break;
- case QPNP_VADC_REV_ID_8026_1_0:
+ case QPNP_REV_ID_8026_1_0:
switch (vadc->id) {
case COMP_ID_TSMC:
temp_var = (((die_temp *
@@ -661,19 +687,47 @@
break;
}
break;
- case QPNP_VADC_REV_ID_8026_2_0:
+ case QPNP_REV_ID_8026_2_0:
+ case QPNP_REV_ID_8026_2_1:
switch (vadc->id) {
case COMP_ID_TSMC:
- temp_var = ((die_temp - 2500) *
+ temp_var = ((die_temp - 25000) *
(-QPNP_VBAT_COEFF_11));
break;
default:
case COMP_ID_GF:
- temp_var = ((die_temp - 2500) *
+ temp_var = ((die_temp - 25000) *
(-QPNP_VBAT_COEFF_9));
break;
}
break;
+ case QPNP_REV_ID_8026_2_2:
+ switch (vadc->id) {
+ case COMP_ID_TSMC:
+ *result -= QPNP_VBAT_COEFF_23;
+ temp_var = 0;
+ break;
+ default:
+ case COMP_ID_GF:
+ *result -= QPNP_VBAT_COEFF_23;
+ temp_var = 0;
+ break;
+ }
+ case QPNP_REV_ID_8110_2_0:
+ switch (vadc->id) {
+ case COMP_ID_SMIC:
+ *result -= QPNP_VBAT_OFFSET_SMIC;
+ temp_var = ((die_temp - 25000) *
+ (QPNP_VBAT_COEFF_17));
+ break;
+ default:
+ case COMP_ID_GF:
+ *result -= QPNP_VBAT_OFFSET_GF;
+ temp_var = ((die_temp - 25000) *
+ (QPNP_VBAT_COEFF_16));
+ break;
+ }
+ break;
default:
temp_var = 0;
break;
@@ -692,7 +746,7 @@
}
int32_t qpnp_vbat_sns_comp_result(struct qpnp_vadc_chip *vadc,
- int64_t *result)
+ int64_t *result, bool is_pon_ocv)
{
struct qpnp_vadc_result die_temp_result;
int rc = 0;
@@ -708,7 +762,12 @@
return rc;
}
- rc = qpnp_ocv_comp(result, vadc, die_temp_result.physical);
+ if (is_pon_ocv)
+ rc = qpnp_ocv_comp(result, vadc, die_temp_result.physical);
+ else
+ rc = qpnp_vbat_sns_comp(result, vadc,
+ die_temp_result.physical);
+
if (rc < 0)
pr_err("Error with vbat compensation\n");
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index b36faff..667da01 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -421,6 +421,12 @@
else if (!mmc_card_sdio(card) && mmc_use_core_runtime_pm(card->host))
pm_runtime_enable(&card->dev);
+ if (mmc_card_sdio(card)) {
+ ret = device_init_wakeup(&card->dev, true);
+ if (ret)
+ pr_err("%s: %s: failed to init wakeup: %d\n",
+ mmc_hostname(card->host), __func__, ret);
+ }
ret = device_add(&card->dev);
if (ret)
return ret;
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index c7fa876..c082f77 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -77,16 +77,40 @@
{
struct mmc_host *host = cls_dev_to_mmc_host(dev);
int ret = 0;
+ unsigned long flags;
if (!mmc_use_core_pm(host))
return 0;
+ spin_lock_irqsave(&host->clk_lock, flags);
+ /*
+ * let the driver know that suspend is in progress and must
+ * be aborted on receiving a sdio card interrupt
+ */
+ host->dev_status = DEV_SUSPENDING;
+ spin_unlock_irqrestore(&host->clk_lock, flags);
if (!pm_runtime_suspended(dev)) {
ret = mmc_suspend_host(host);
if (ret < 0)
pr_err("%s: %s: failed: ret: %d\n", mmc_hostname(host),
__func__, ret);
}
+ /*
+ * If SDIO function driver doesn't want to power off the card,
+ * atleast turn off clocks to allow deep sleep.
+ */
+ if (!ret && host->card && mmc_card_sdio(host->card) &&
+ host->ios.clock) {
+ spin_lock_irqsave(&host->clk_lock, flags);
+ host->clk_old = host->ios.clock;
+ host->ios.clock = 0;
+ host->clk_gated = true;
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+ mmc_set_ios(host);
+ }
+ spin_lock_irqsave(&host->clk_lock, flags);
+ host->dev_status = DEV_SUSPENDED;
+ spin_unlock_irqrestore(&host->clk_lock, flags);
return ret;
}
@@ -104,6 +128,7 @@
pr_err("%s: %s: failed: ret: %d\n", mmc_hostname(host),
__func__, ret);
}
+ host->dev_status = DEV_RESUMED;
return ret;
}
diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c
index 4407d91..d517205 100644
--- a/drivers/mmc/core/quirks.c
+++ b/drivers/mmc/core/quirks.c
@@ -50,6 +50,14 @@
#define SDIO_DEVICE_ID_MSM_QCA_AR6003_2 0x301
#endif
+#ifndef SDIO_DEVICE_ID_MSM_QCA_AR6004_1
+#define SDIO_DEVICE_ID_MSM_QCA_AR6004_1 0x400
+#endif
+
+#ifndef SDIO_DEVICE_ID_MSM_QCA_AR6004_2
+#define SDIO_DEVICE_ID_MSM_QCA_AR6004_2 0x401
+#endif
+
/*
* This hook just adds a quirk for all sdio devices
*/
@@ -78,6 +86,12 @@
SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6003_2,
remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
+ SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6004_1,
+ remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
+
+ SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6004_2,
+ remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
+
SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index 3d8ceb4..2b48f77 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -85,6 +85,7 @@
struct sched_param param = { .sched_priority = 1 };
unsigned long period, idle_period;
int ret;
+ bool ws;
sched_setscheduler(current, SCHED_FIFO, ¶m);
@@ -118,6 +119,17 @@
ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort);
if (ret)
break;
+ ws = false;
+ /*
+ * prevent suspend if it has started when scheduled;
+ * 100 msec (approx. value) should be enough for the system to
+ * resume and attend to the card's request
+ */
+ if ((host->dev_status == DEV_SUSPENDING) ||
+ (host->dev_status == DEV_SUSPENDED)) {
+ pm_wakeup_event(&host->card->dev, 100);
+ ws = true;
+ }
ret = process_sdio_pending_irqs(host);
host->sdio_irq_pending = false;
mmc_release_host(host);
@@ -154,6 +166,12 @@
host->ops->enable_sdio_irq(host, 1);
mmc_host_clk_release(host);
}
+ /*
+ * function drivers would have processed the event from card
+ * unless suspended, hence release wake source
+ */
+ if (ws && (host->dev_status == DEV_RESUMED))
+ pm_relax(&host->card->dev);
if (!kthread_should_stop())
schedule_timeout(period);
set_current_state(TASK_RUNNING);
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 739a237..d3a0e9e 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -31,6 +31,7 @@
#include <linux/delay.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
+#include <linux/irq.h>
#include <linux/mmc/mmc.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
@@ -38,10 +39,18 @@
#include <linux/dma-mapping.h>
#include <mach/gpio.h>
#include <mach/msm_bus.h>
+#include <mach/mpm.h>
#include <linux/iopoll.h>
#include "sdhci-pltfm.h"
+enum sdc_mpm_pin_state {
+ SDC_DAT1_DISABLE,
+ SDC_DAT1_ENABLE,
+ SDC_DAT1_ENWAKE,
+ SDC_DAT1_DISWAKE,
+};
+
#define SDHCI_VER_100 0x2B
#define CORE_HC_MODE 0x78
#define HC_MODE_EN 0x1
@@ -156,6 +165,9 @@
#define INVALID_TUNING_PHASE -1
+#define sdhci_is_valid_mpm_wakeup_int(_h) ((_h)->pdata->mpm_sdiowakeup_int >= 0)
+#define sdhci_is_valid_gpio_wakeup_int(_h) ((_h)->pdata->sdiowakeup_irq >= 0)
+
static const u32 tuning_block_64[] = {
0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
@@ -283,6 +295,8 @@
struct sdhci_msm_bus_voting_data *voting_data;
u32 *sup_clk_table;
unsigned char sup_clk_cnt;
+ int mpm_sdiowakeup_int;
+ int sdiowakeup_irq;
};
struct sdhci_msm_bus_vote {
@@ -318,6 +332,7 @@
bool calibration_done;
u8 saved_tuning_phase;
atomic_t controller_clock;
+ bool is_sdiowakeup_enabled;
};
enum vdd_io_level {
@@ -1338,7 +1353,7 @@
struct device_node *np = dev->of_node;
u32 bus_width = 0;
u32 cpu_dma_latency;
- int len, i;
+ int len, i, mpm_int;
int clk_table_len;
u32 *clk_table = NULL;
enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
@@ -1433,6 +1448,12 @@
if (of_get_property(np, "qcom,nonremovable", NULL))
pdata->nonremovable = true;
+ if (!of_property_read_u32(np, "qcom,dat1-mpm-int",
+ &mpm_int))
+ pdata->mpm_sdiowakeup_int = mpm_int;
+ else
+ pdata->mpm_sdiowakeup_int = -1;
+
return pdata;
out:
return NULL;
@@ -1933,6 +1954,39 @@
return ret;
}
+/*
+ * Acquire spin-lock host->lock before calling this function
+ */
+static void sdhci_msm_cfg_sdiowakeup_gpio_irq(struct sdhci_host *host,
+ bool enable)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+
+ if (enable && !msm_host->is_sdiowakeup_enabled)
+ enable_irq(msm_host->pdata->sdiowakeup_irq);
+ else if (!enable && msm_host->is_sdiowakeup_enabled)
+ disable_irq_nosync(msm_host->pdata->sdiowakeup_irq);
+ else
+ dev_warn(&msm_host->pdev->dev, "%s: wakeup to config: %d curr: %d\n",
+ __func__, enable, msm_host->is_sdiowakeup_enabled);
+ msm_host->is_sdiowakeup_enabled = enable;
+}
+
+static irqreturn_t sdhci_msm_sdiowakeup_irq(int irq, void *data)
+{
+ struct sdhci_host *host = (struct sdhci_host *)data;
+ unsigned long flags;
+
+ pr_debug("%s: irq (%d) received\n", __func__, irq);
+
+ spin_lock_irqsave(&host->lock, flags);
+ sdhci_msm_cfg_sdiowakeup_gpio_irq(host, false);
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
{
struct sdhci_host *host = (struct sdhci_host *)data;
@@ -2609,6 +2663,38 @@
.enable_controller_clock = sdhci_msm_enable_controller_clock,
};
+static int sdhci_msm_cfg_mpm_pin_wakeup(struct sdhci_host *host, unsigned mode)
+{
+ int ret = 0;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ unsigned int pin = msm_host->pdata->mpm_sdiowakeup_int;
+
+ if (!pin)
+ return 0;
+
+ switch (mode) {
+ case SDC_DAT1_DISABLE:
+ ret = msm_mpm_enable_pin(pin, 0);
+ break;
+ case SDC_DAT1_ENABLE:
+ ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
+ if (!ret)
+ ret = msm_mpm_enable_pin(pin, 1);
+ break;
+ case SDC_DAT1_ENWAKE:
+ ret = msm_mpm_set_pin_wake(pin, 1);
+ break;
+ case SDC_DAT1_DISWAKE:
+ ret = msm_mpm_set_pin_wake(pin, 0);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
static int __devinit sdhci_msm_probe(struct platform_device *pdev)
{
struct sdhci_host *host;
@@ -2619,6 +2705,7 @@
u32 vdd_max_current;
u16 host_version;
u32 pwr, irq_status, irq_ctl;
+ unsigned long flags;
pr_debug("%s: Enter %s\n", dev_name(&pdev->dev), __func__);
msm_host = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_msm_host),
@@ -2837,6 +2924,8 @@
host->quirks2 |= SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT;
}
+ host->quirks2 |= SDHCI_QUIRK2_IGN_DATA_END_BIT_ERROR;
+
/* Setup PWRCTL irq */
msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
if (msm_host->pwr_irq < 0) {
@@ -2891,7 +2980,7 @@
msm_host->mmc->caps2 |= MMC_CAP2_STOP_REQUEST;
msm_host->mmc->caps2 |= MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE;
msm_host->mmc->caps2 |= MMC_CAP2_CORE_PM;
- msm_host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
+ msm_host->mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
if (msm_host->pdata->nonremovable)
msm_host->mmc->caps |= MMC_CAP_NONREMOVABLE;
@@ -2917,6 +3006,27 @@
dev_err(&pdev->dev, "%s: Failed to set dma mask\n", __func__);
}
+ msm_host->pdata->sdiowakeup_irq = platform_get_irq_byname(pdev,
+ "sdiowakeup_irq");
+ if (msm_host->pdata->sdiowakeup_irq >= 0) {
+ msm_host->is_sdiowakeup_enabled = true;
+ ret = request_irq(msm_host->pdata->sdiowakeup_irq,
+ sdhci_msm_sdiowakeup_irq,
+ IRQF_SHARED | IRQF_TRIGGER_LOW,
+ "sdhci-msm sdiowakeup", host);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: request sdiowakeup IRQ %d: failed: %d\n",
+ __func__, msm_host->pdata->sdiowakeup_irq, ret);
+ msm_host->pdata->sdiowakeup_irq = -1;
+ msm_host->is_sdiowakeup_enabled = false;
+ goto free_cd_gpio;
+ } else {
+ spin_lock_irqsave(&host->lock, flags);
+ sdhci_msm_cfg_sdiowakeup_gpio_irq(host, false);
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+ }
+
ret = sdhci_add_host(host);
if (ret) {
dev_err(&pdev->dev, "Add host failed (%d)\n", ret);
@@ -2950,6 +3060,16 @@
else if (mmc_use_core_runtime_pm(host->mmc))
pm_runtime_enable(&pdev->dev);
+ if (msm_host->pdata->mpm_sdiowakeup_int != -1) {
+ ret = sdhci_msm_cfg_mpm_pin_wakeup(host, SDC_DAT1_ENABLE);
+ if (ret) {
+ pr_err("%s: enabling wakeup: failed: ret: %d\n",
+ mmc_hostname(host->mmc), ret);
+ ret = 0;
+ msm_host->pdata->mpm_sdiowakeup_int = -1;
+ }
+ }
+
/* Successful initialization */
goto out;
@@ -2961,6 +3081,8 @@
free_cd_gpio:
if (gpio_is_valid(msm_host->pdata->status_gpio))
mmc_cd_gpio_free(msm_host->mmc);
+ if (sdhci_is_valid_gpio_wakeup_int(msm_host))
+ free_irq(msm_host->pdata->sdiowakeup_irq, host);
vreg_deinit:
sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false);
bus_unregister:
@@ -3006,6 +3128,12 @@
pm_runtime_disable(&pdev->dev);
sdhci_pltfm_free(pdev);
+ if (sdhci_is_valid_mpm_wakeup_int(msm_host))
+ sdhci_msm_cfg_mpm_pin_wakeup(host, SDC_DAT1_DISABLE);
+
+ if (sdhci_is_valid_gpio_wakeup_int(msm_host))
+ free_irq(msm_host->pdata->sdiowakeup_irq, host);
+
if (gpio_is_valid(msm_host->pdata->status_gpio))
mmc_cd_gpio_free(msm_host->mmc);
@@ -3021,13 +3149,75 @@
return 0;
}
+static int sdhci_msm_cfg_sdio_wakeup(struct sdhci_host *host, bool enable)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ unsigned long flags;
+ int ret = 0;
+
+ if (!(host->mmc->card && mmc_card_sdio(host->mmc->card) &&
+ (sdhci_is_valid_mpm_wakeup_int(msm_host) ||
+ sdhci_is_valid_gpio_wakeup_int(msm_host)) &&
+ mmc_card_wake_sdio_irq(host->mmc))) {
+ return 1;
+ }
+
+ spin_lock_irqsave(&host->lock, flags);
+ if (enable) {
+ /* configure DAT1 gpio if applicable */
+ if (sdhci_is_valid_gpio_wakeup_int(msm_host)) {
+ ret = enable_irq_wake(msm_host->pdata->sdiowakeup_irq);
+ if (!ret)
+ sdhci_msm_cfg_sdiowakeup_gpio_irq(host, true);
+ goto out;
+ } else {
+ ret = sdhci_msm_cfg_mpm_pin_wakeup(host,
+ SDC_DAT1_ENWAKE);
+ if (ret)
+ goto out;
+ ret = enable_irq_wake(host->irq);
+ if (ret)
+ sdhci_msm_cfg_mpm_pin_wakeup(host,
+ SDC_DAT1_DISWAKE);
+ }
+ } else {
+ if (sdhci_is_valid_gpio_wakeup_int(msm_host)) {
+ ret = disable_irq_wake(msm_host->pdata->sdiowakeup_irq);
+ sdhci_msm_cfg_sdiowakeup_gpio_irq(host, false);
+ } else {
+ ret = sdhci_msm_cfg_mpm_pin_wakeup(host,
+ SDC_DAT1_DISWAKE);
+ if (ret)
+ goto out;
+ ret = disable_irq_wake(host->irq);
+ }
+ }
+out:
+ if (ret)
+ pr_err("%s: %s: %sable wakeup: failed: %d gpio: %d mpm: %d\n",
+ mmc_hostname(host->mmc), __func__, enable ? "en" : "dis",
+ ret, msm_host->pdata->sdiowakeup_irq,
+ msm_host->pdata->mpm_sdiowakeup_int);
+ spin_unlock_irqrestore(&host->lock, flags);
+ return ret;
+}
+
static int sdhci_msm_runtime_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ int ret;
+
+ ret = sdhci_msm_cfg_sdio_wakeup(host, true);
+ /* pwr_irq is not monitored by mpm on suspend, hence disable it */
+ if (!ret)
+ goto skip_disable_host_irq;
disable_irq(host->irq);
+
+skip_disable_host_irq:
disable_irq(msm_host->pwr_irq);
/*
@@ -3048,10 +3238,17 @@
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ int ret;
- enable_irq(msm_host->pwr_irq);
+ ret = sdhci_msm_cfg_sdio_wakeup(host, false);
+ if (!ret)
+ goto skip_enable_host_irq;
+
enable_irq(host->irq);
+skip_enable_host_irq:
+ enable_irq(msm_host->pwr_irq);
+
return 0;
}
@@ -3103,6 +3300,26 @@
out:
return ret;
}
+
+static int sdhci_msm_suspend_noirq(struct device *dev)
+{
+ struct sdhci_host *host = dev_get_drvdata(dev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ int ret = 0;
+
+ /*
+ * ksdioirqd may get scheduled after sdhc suspend, hence retry
+ * suspend in case the clocks are ON
+ */
+ if (atomic_read(&msm_host->clks_on)) {
+ pr_warn("%s: %s: clock ON after suspend, aborting suspend\n",
+ mmc_hostname(host->mmc), __func__);
+ ret = -EAGAIN;
+ }
+
+ return ret;
+}
#endif
#ifdef CONFIG_PM
@@ -3110,6 +3327,7 @@
SET_SYSTEM_SLEEP_PM_OPS(sdhci_msm_suspend, sdhci_msm_resume)
SET_RUNTIME_PM_OPS(sdhci_msm_runtime_suspend, sdhci_msm_runtime_resume,
NULL)
+ .suspend_noirq = sdhci_msm_suspend_noirq,
};
#define SDHCI_MSM_PMOPS (&sdhci_msm_pmops)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 822548e..32ff175 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -32,6 +32,7 @@
#include "sdhci.h"
#define DRIVER_NAME "sdhci"
+#define SDHCI_SUSPEND_TIMEOUT 300 /* 300 ms */
#define DBG(f, x...) \
pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
@@ -68,6 +69,12 @@
}
#endif
+static inline int sdhci_get_async_int_status(struct sdhci_host *host)
+{
+ return (sdhci_readw(host, SDHCI_HOST_CONTROL2) &
+ SDHCI_CTRL_ASYNC_INT_ENABLE) >> 14;
+}
+
static void sdhci_dump_state(struct sdhci_host *host)
{
struct mmc_host *mmc = host->mmc;
@@ -1579,6 +1586,33 @@
spin_unlock_irqrestore(&host->lock, flags);
}
+static void sdhci_cfg_async_intr(struct sdhci_host *host, bool enable)
+{
+ if (!host->async_int_supp)
+ return;
+
+ if (enable)
+ sdhci_writew(host,
+ sdhci_readw(host, SDHCI_HOST_CONTROL2) |
+ SDHCI_CTRL_ASYNC_INT_ENABLE,
+ SDHCI_HOST_CONTROL2);
+ else
+ sdhci_writew(host, sdhci_readw(host, SDHCI_HOST_CONTROL2) &
+ ~SDHCI_CTRL_ASYNC_INT_ENABLE,
+ SDHCI_HOST_CONTROL2);
+}
+
+static void sdhci_cfg_irq(struct sdhci_host *host, bool enable)
+{
+ if (enable && !host->irq_enabled) {
+ enable_irq(host->irq);
+ host->irq_enabled = true;
+ } else if (!enable && host->irq_enabled) {
+ disable_irq_nosync(host->irq);
+ host->irq_enabled = false;
+ }
+}
+
static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
{
unsigned long flags;
@@ -1594,9 +1628,26 @@
return;
}
- if (ios->clock)
+ spin_lock_irqsave(&host->lock, flags);
+ /* lock is being released intermittently below, hence disable irq */
+ sdhci_cfg_irq(host, false);
+ spin_unlock_irqrestore(&host->lock, flags);
+ if (ios->clock) {
sdhci_set_clock(host, ios->clock);
-
+ if (host->async_int_supp && sdhci_get_async_int_status(host)) {
+ if (host->disable_sdio_irq_deferred) {
+ pr_debug("%s: %s: disable sdio irq\n",
+ mmc_hostname(host->mmc), __func__);
+ host->mmc->ops->enable_sdio_irq(host->mmc, 0);
+ host->disable_sdio_irq_deferred = false;
+ }
+ spin_lock_irqsave(&host->lock, flags);
+ sdhci_cfg_async_intr(host, false);
+ spin_unlock_irqrestore(&host->lock, flags);
+ pr_debug("%s: %s: unconfig async intr\n",
+ mmc_hostname(host->mmc), __func__);
+ }
+ }
/*
* The controller clocks may be off during power-up and we may end up
* enabling card clock before giving power to the card. Hence, during
@@ -1622,6 +1673,7 @@
}
spin_lock_irqsave(&host->lock, flags);
if (!host->clock) {
+ sdhci_cfg_irq(host, true);
spin_unlock_irqrestore(&host->lock, flags);
mutex_unlock(&host->ios_mutex);
return;
@@ -1781,9 +1833,18 @@
if (host->vmmc && vdd_bit != -1)
mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit);
}
- if (!ios->clock)
+ if (!ios->clock) {
+ if (host->async_int_supp && host->mmc->card &&
+ mmc_card_sdio(host->mmc->card)) {
+ sdhci_cfg_async_intr(host, true);
+ pr_debug("%s: %s: config async intr\n",
+ mmc_hostname(host->mmc), __func__);
+ }
sdhci_set_clock(host, ios->clock);
-
+ }
+ spin_lock_irqsave(&host->lock, flags);
+ sdhci_cfg_irq(host, true);
+ spin_unlock_irqrestore(&host->lock, flags);
mmiowb();
mutex_unlock(&host->ios_mutex);
}
@@ -1863,6 +1924,14 @@
if (host->flags & SDHCI_DEVICE_DEAD)
goto out;
+ if (!enable && !host->clock) {
+ pr_debug("%s: %s: defered disabling card intr\n",
+ host->mmc ? mmc_hostname(host->mmc) : "null",
+ __func__);
+ host->disable_sdio_irq_deferred = true;
+ return;
+ }
+
if (enable)
host->flags |= SDHCI_SDIO_IRQ_ENABLED;
else
@@ -2742,6 +2811,23 @@
return IRQ_HANDLED;
}
+ if (!host->clock && host->mmc->card &&
+ mmc_card_sdio(host->mmc->card)) {
+ /* SDIO async. interrupt is level-sensitive */
+ sdhci_cfg_irq(host, false);
+ pr_debug("%s: got async-irq: clocks: %d gated: %d host-irq[en:1/dis:0]: %d\n",
+ mmc_hostname(host->mmc), host->clock,
+ host->mmc->clk_gated, host->irq_enabled);
+ spin_unlock(&host->lock);
+ /* prevent suspend till the ksdioirqd runs or resume happens */
+ if ((host->mmc->dev_status == DEV_SUSPENDING) ||
+ (host->mmc->dev_status == DEV_SUSPENDED))
+ pm_wakeup_event(&host->mmc->card->dev,
+ SDHCI_SUSPEND_TIMEOUT);
+ else
+ mmc_signal_sdio_irq(host->mmc);
+ return IRQ_HANDLED;
+ }
intmask = sdhci_readl(host, SDHCI_INT_STATUS);
if (!intmask || intmask == 0xffffffff) {
@@ -2837,9 +2923,13 @@
/*
* We have to delay this as it calls back into the driver.
*/
- if (cardint)
+ if (cardint) {
+ /* clks are on, but suspend may be in progress */
+ if (host->mmc->dev_status == DEV_SUSPENDING)
+ pm_wakeup_event(&host->mmc->card->dev,
+ SDHCI_SUSPEND_TIMEOUT);
mmc_signal_sdio_irq(host->mmc);
-
+ }
return result;
}
@@ -3489,6 +3579,7 @@
if (ret)
goto untasklet;
+ host->irq_enabled = true;
host->vmmc = regulator_get(mmc_dev(mmc), "vmmc");
if (IS_ERR(host->vmmc)) {
pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc));
@@ -3532,8 +3623,12 @@
mmc_hostname(mmc), ret);
}
+ if (caps[0] & SDHCI_ASYNC_INTR)
+ host->async_int_supp = true;
mmc_add_host(mmc);
+ if (host->quirks2 & SDHCI_QUIRK2_IGN_DATA_END_BIT_ERROR)
+ sdhci_clear_set_irqs(host, SDHCI_INT_DATA_END_BIT, 0);
pr_info("%s: SDHCI controller on %s [%s] using %s\n",
mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)),
(host->flags & SDHCI_USE_ADMA) ? "ADMA" :
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index db4806d..8c2320b 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -175,6 +175,7 @@
#define SDHCI_CTRL_DRV_TYPE_D 0x0030
#define SDHCI_CTRL_EXEC_TUNING 0x0040
#define SDHCI_CTRL_TUNED_CLK 0x0080
+#define SDHCI_CTRL_ASYNC_INT_ENABLE 0x4000
#define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000
#define SDHCI_CAPABILITIES 0x40
@@ -195,6 +196,7 @@
#define SDHCI_CAN_VDD_300 0x02000000
#define SDHCI_CAN_VDD_180 0x04000000
#define SDHCI_CAN_64BIT 0x10000000
+#define SDHCI_ASYNC_INTR 0x20000000
#define SDHCI_SUPPORT_SDR50 0x00000001
#define SDHCI_SUPPORT_SDR104 0x00000002
diff --git a/drivers/nfc/nfc-nci.c b/drivers/nfc/nfc-nci.c
index a44c06c..9d8b780 100644
--- a/drivers/nfc/nfc-nci.c
+++ b/drivers/nfc/nfc-nci.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
+#include <linux/reboot.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/irq.h>
@@ -47,7 +48,7 @@
MODULE_DEVICE_TABLE(of, msm_match_table);
#define MAX_BUFFER_SIZE (780)
-#define PACKET_MAX_LENGTH (258)
+#define PACKET_MAX_LENGTH (258)
/* Read data */
#define PACKET_HEADER_SIZE_NCI (4)
#define PACKET_TYPE_NCI (16)
@@ -58,7 +59,7 @@
#define NTF_TIMEOUT (10000)
#define CORE_RESET_RSP_GID (0x60)
#define CORE_RESET_OID (0x00)
-#define CORE_RST_NTF_LENGTH (0x02)
+#define CORE_RST_NTF_LENGTH (0x02)
static void clk_req_update(struct work_struct *work);
@@ -115,6 +116,9 @@
static int ftm_werr_code;
+unsigned int disable_ctrl;
+bool region2_sent;
+
static void qca199x_init_stat(struct qca199x_dev *qca199x_dev)
{
qca199x_dev->count_irq = 0;
@@ -491,6 +495,12 @@
}
mutex_unlock(&qca199x_dev->read_mutex);
+ /* If we detect a Region2 command prior to power-down */
+ if ((tmp[0] == 0x2F) && (tmp[1] == 0x01) && (tmp[2] == 0x02) &&
+ (tmp[3] == 0x08) && (tmp[4] == 0x00)) {
+ region2_sent = true;
+ }
+
return ret;
}
@@ -606,7 +616,7 @@
if (r < 0)
goto err_req;
/*
- Also, set flag for initial NCI write following resetas
+ Also, set flag for initial NCI write following reset as
may wish to do some house keeping. Ensure no pending
messages in NFCC buffers which may be wrongly
construed as response to initial message
@@ -718,7 +728,7 @@
int r = 0;
unsigned short slave_addr = 0xE;
unsigned short curr_addr;
-
+ unsigned char raw_nci_wake[] = {0x10, 0x0F};
unsigned char raw_chip_version_addr = 0x00;
unsigned char raw_chip_rev_id_addr = 0x9C;
unsigned char raw_chip_version = 0xFF;
@@ -728,9 +738,22 @@
platform_data = qca199x_dev->client->dev.platform_data;
+ /*
+ * Always wake up chip when reading 0x9C, otherwise this
+ * register is not updated
+ */
+ curr_addr = qca199x_dev->client->addr;
+ qca199x_dev->client->addr = slave_addr;
+ r = nfc_i2c_write(qca199x_dev->client, &raw_nci_wake[0],
+ sizeof(raw_nci_wake));
+ r = sizeof(raw_nci_wake);
+ if (r != sizeof(raw_nci_wake))
+ goto invalid_wake_up;
+ qca199x_dev->state = NFCC_STATE_NORMAL_WAKE;
+
+ /* sleep to ensure the NFCC has time to wake up */
+ usleep(100);
if (arg == 0) {
- curr_addr = qca199x_dev->client->addr;
- qca199x_dev->client->addr = slave_addr;
r = nfc_i2c_write(qca199x_dev->client,
&raw_chip_version_addr, 1);
if (r < 0)
@@ -739,10 +762,7 @@
r = i2c_master_recv(qca199x_dev->client, &raw_chip_version, 1);
/* Restore original NFCC slave I2C address */
qca199x_dev->client->addr = curr_addr;
- }
- if (arg == 1) {
- curr_addr = qca199x_dev->client->addr;
- qca199x_dev->client->addr = slave_addr;
+ } else if (arg == 1) {
r = nfc_i2c_write(qca199x_dev->client,
&raw_chip_rev_id_addr, 1);
if (r < 0)
@@ -752,8 +772,9 @@
/* Restore original NFCC slave I2C address */
qca199x_dev->client->addr = curr_addr;
}
-
return raw_chip_version;
+invalid_wake_up:
+ raw_chip_version = 0xFE;
invalid_wr:
raw_chip_version = 0xFF;
dev_err(&qca199x_dev->client->dev,
@@ -929,121 +950,117 @@
if (r < 0)
goto err_init;
- if (0x10 != (0x10 & buf)) {
- RAW(s73, 0x02);
+ RAW(s73, 0x02);
- r = nfc_i2c_write(client, &raw_s73[0], sizeof(raw_s73));
- if (r < 0)
- goto err_init;
-
- usleep(1000);
- RAW(1p8_CONTROL_011, XTAL_CLOCK | 0x01);
-
- r = nfc_i2c_write(client, &raw_1p8_CONTROL_011[0],
- sizeof(raw_1p8_CONTROL_011));
- if (r < 0)
- goto err_init;
-
- usleep(1000);
- RAW(1P8_CONTROL_010, (0x8));
- r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
- sizeof(raw_1P8_CONTROL_010));
- if (r < 0)
- goto err_init;
-
- usleep(10000); /* 10ms wait */
- RAW(1P8_CONTROL_010, (0xC));
- r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
- sizeof(raw_1P8_CONTROL_010));
- if (r < 0)
- goto err_init;
-
- usleep(100); /* 100uS wait */
- RAW(1P8_X0_0B0, (FREQ_SEL_19));
- r = nfc_i2c_write(client, &raw_1P8_X0_0B0[0],
- sizeof(raw_1P8_X0_0B0));
- if (r < 0)
- goto err_init;
-
- usleep(1000);
-
- /* PWR_EN = 1 */
- RAW(1P8_CONTROL_010, (0xd));
- r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
- sizeof(raw_1P8_CONTROL_010));
- if (r < 0)
- goto err_init;
-
-
- usleep(20000); /* 20ms wait */
- /* LS_EN = 1 */
- RAW(1P8_CONTROL_010, 0xF);
- r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
- sizeof(raw_1P8_CONTROL_010));
- if (r < 0)
- goto err_init;
-
- usleep(20000); /* 20ms wait */
-
- /* Enable the PMIC clock */
- RAW(1P8_PAD_CFG_CLK_REQ, (0x1));
- r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_CLK_REQ[0],
- sizeof(raw_1P8_PAD_CFG_CLK_REQ));
- if (r < 0)
- goto err_init;
-
- usleep(1000);
-
- RAW(1P8_PAD_CFG_PWR_REQ, (0x1));
- r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_PWR_REQ[0],
- sizeof(raw_1P8_PAD_CFG_PWR_REQ));
- if (r < 0)
- goto err_init;
-
- usleep(1000);
-
- RAW(slave2, 0x10);
- r = nfc_i2c_write(client, &raw_slave2[0], sizeof(raw_slave2));
- if (r < 0)
- goto err_init;
-
- usleep(1000);
-
- RAW(slave1, NCI_I2C_SLAVE);
- r = nfc_i2c_write(client, &raw_slave1[0], sizeof(raw_slave1));
- if (r < 0)
- goto err_init;
-
- usleep(1000);
-
- /* QCA199x NFCC CPU should now boot... */
- r = i2c_master_recv(client, &raw_slave1_rd, 1);
- /* Talk on NCI slave address NCI_I2C_SLAVE 0x2C*/
- client->addr = NCI_I2C_SLAVE;
-
- /*
- Start with small delay and then we will poll until we
- get a core reset notification - This is time for chip
- & NFCC controller to come-up.
- */
- usleep(1000); /* 1 ms */
-
- do {
- ret = i2c_master_recv(client, rsp, 5);
- /* Found core reset notification */
- if (((rsp[0] == CORE_RESET_RSP_GID) &&
- (rsp[1] == CORE_RESET_OID) &&
- (rsp[2] == CORE_RST_NTF_LENGTH))
- || time_taken == NTF_TIMEOUT) {
- core_reset_completed = true;
- }
- usleep(10); /* 10us sleep before retry */
- time_taken++;
- } while (!core_reset_completed);
- r = 0;
- } else {
+ r = nfc_i2c_write(client, &raw_s73[0], sizeof(raw_s73));
+ if (r < 0)
goto err_init;
- }
+
+ usleep(1000);
+ RAW(1p8_CONTROL_011, XTAL_CLOCK | 0x01);
+
+ r = nfc_i2c_write(client, &raw_1p8_CONTROL_011[0],
+ sizeof(raw_1p8_CONTROL_011));
+ if (r < 0)
+ goto err_init;
+
+ usleep(1000);
+ RAW(1P8_CONTROL_010, (0x8));
+ r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+ sizeof(raw_1P8_CONTROL_010));
+ if (r < 0)
+ goto err_init;
+
+ usleep(10000); /* 10ms wait */
+ RAW(1P8_CONTROL_010, (0xC));
+ r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+ sizeof(raw_1P8_CONTROL_010));
+ if (r < 0)
+ goto err_init;
+
+ usleep(100); /* 100uS wait */
+ RAW(1P8_X0_0B0, (FREQ_SEL_19));
+ r = nfc_i2c_write(client, &raw_1P8_X0_0B0[0],
+ sizeof(raw_1P8_X0_0B0));
+ if (r < 0)
+ goto err_init;
+
+ usleep(1000);
+
+ /* PWR_EN = 1 */
+ RAW(1P8_CONTROL_010, (0xd));
+ r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+ sizeof(raw_1P8_CONTROL_010));
+ if (r < 0)
+ goto err_init;
+
+
+ usleep(20000); /* 20ms wait */
+ /* LS_EN = 1 */
+ RAW(1P8_CONTROL_010, 0xF);
+ r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+ sizeof(raw_1P8_CONTROL_010));
+ if (r < 0)
+ goto err_init;
+
+ usleep(20000); /* 20ms wait */
+
+ /* Enable the PMIC clock */
+ RAW(1P8_PAD_CFG_CLK_REQ, (0x1));
+ r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_CLK_REQ[0],
+ sizeof(raw_1P8_PAD_CFG_CLK_REQ));
+ if (r < 0)
+ goto err_init;
+
+ usleep(1000);
+
+ RAW(1P8_PAD_CFG_PWR_REQ, (0x1));
+ r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_PWR_REQ[0],
+ sizeof(raw_1P8_PAD_CFG_PWR_REQ));
+ if (r < 0)
+ goto err_init;
+
+ usleep(1000);
+
+ RAW(slave2, 0x10);
+ r = nfc_i2c_write(client, &raw_slave2[0], sizeof(raw_slave2));
+ if (r < 0)
+ goto err_init;
+
+ usleep(1000);
+
+ RAW(slave1, NCI_I2C_SLAVE);
+ r = nfc_i2c_write(client, &raw_slave1[0], sizeof(raw_slave1));
+ if (r < 0)
+ goto err_init;
+
+ usleep(1000);
+
+ /* QCA199x NFCC CPU should now boot... */
+ r = i2c_master_recv(client, &raw_slave1_rd, 1);
+ /* Talk on NCI slave address NCI_I2C_SLAVE 0x2C*/
+ client->addr = NCI_I2C_SLAVE;
+
+ /*
+ Start with small delay and then we will poll until we
+ get a core reset notification - This is time for chip
+ & NFCC controller to come-up.
+ */
+ usleep(1000); /* 1 ms */
+
+ do {
+ ret = i2c_master_recv(client, rsp, 5);
+ /* Found core reset notification */
+ if (((rsp[0] == CORE_RESET_RSP_GID) &&
+ (rsp[1] == CORE_RESET_OID) &&
+ (rsp[2] == CORE_RST_NTF_LENGTH))
+ || time_taken == NTF_TIMEOUT) {
+ core_reset_completed = true;
+ }
+ usleep(10); /* 10us sleep before retry */
+ time_taken++;
+ } while (!core_reset_completed);
+ r = 0;
return r;
err_init:
r = 1;
@@ -1143,6 +1160,7 @@
pdata->dis_gpio = of_get_named_gpio(np, "qcom,dis-gpio", 0);
if ((!gpio_is_valid(pdata->dis_gpio)))
return -EINVAL;
+ disable_ctrl = pdata->dis_gpio;
pdata->irq_gpio = of_get_named_gpio(np, "qcom,irq-gpio", 0);
if ((!gpio_is_valid(pdata->irq_gpio)))
@@ -1246,8 +1264,12 @@
goto err_free_dev;
}
- /* Put device in ULPM */
- gpio_set_value(platform_data->dis_gpio, 0);
+ /* Guarantee that the NFCC starts in a clean state. */
+ gpio_set_value(platform_data->dis_gpio, 1);/* HPD */
+ usleep(200);
+ gpio_set_value(platform_data->dis_gpio, 0);/* ULPM */
+ usleep(200);
+
r = nfcc_hw_check(client, platform_data->reg);
if (r) {
/* We don't think there is hardware but just in case HPD */
@@ -1439,6 +1461,10 @@
}
i2c_set_clientdata(client, qca199x_dev);
gpio_set_value(platform_data->dis_gpio, 1);
+
+ /* To keep track if region2 command has been sent to controller */
+ region2_sent = false;
+
dev_dbg(&client->dev,
"nfc-nci probe: %s, probing qca1990 exited successfully\n",
__func__);
@@ -1513,17 +1539,52 @@
},
};
+
+static int nfcc_reboot(struct notifier_block *notifier, unsigned long val,
+ void *v)
+{
+ /*
+ * Set DISABLE=1 *ONLY* if the NFC service has been disabled.
+ * This will put NFCC into HPD(Hard Power Down) state for power
+ * saving when powering down(Low Batt. or Power off handset)
+ * If user requires NFC and CE mode when powered down(PD) the
+ * middleware puts NFCC into region2 prior to PD. In this case
+ * we DO NOT HPD chip as this will trash Region2 and CE support
+ * when handset is PD.
+ */
+ if (region2_sent == false) {
+ /* HPD the NFCC */
+ gpio_set_value(disable_ctrl, 1);
+ }
+ return NOTIFY_OK;
+}
+
+
+static struct notifier_block nfcc_notifier = {
+ .notifier_call = nfcc_reboot,
+ .next = NULL,
+ .priority = 0
+};
+
/*
* module load/unload record keeping
*/
static int __init qca199x_dev_init(void)
{
+ int ret;
+
+ ret = register_reboot_notifier(&nfcc_notifier);
+ if (ret) {
+ pr_err("cannot register reboot notifier (err=%d)\n", ret);
+ return ret;
+ }
return i2c_add_driver(&qca199x);
}
module_init(qca199x_dev_init);
static void __exit qca199x_dev_exit(void)
{
+ unregister_reboot_notifier(&nfcc_notifier);
i2c_del_driver(&qca199x);
}
module_exit(qca199x_dev_exit);
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 82c61c9..56d4a30 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -491,7 +491,7 @@
}
static inline int convert_vbatt_raw_to_uv(struct qpnp_bms_chip *chip,
- uint16_t reading)
+ uint16_t reading, bool is_pon_ocv)
{
int64_t uv;
int rc;
@@ -500,7 +500,7 @@
pr_debug("%u raw converted into %lld uv\n", reading, uv);
uv = adjust_vbatt_reading(chip, uv);
pr_debug("adjusted into %lld uv\n", uv);
- rc = qpnp_vbat_sns_comp_result(chip->vadc_dev, &uv);
+ rc = qpnp_vbat_sns_comp_result(chip->vadc_dev, &uv, is_pon_ocv);
if (rc)
pr_debug("could not compensate vbatt\n");
pr_debug("compensated into %lld uv\n", uv);
@@ -699,7 +699,7 @@
static void convert_and_store_ocv(struct qpnp_bms_chip *chip,
struct raw_soc_params *raw,
- int batt_temp)
+ int batt_temp, bool is_pon_ocv)
{
int rc;
@@ -711,7 +711,7 @@
pr_err("Vadc reference voltage read failed, rc = %d\n", rc);
chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
raw->last_good_ocv_uv = convert_vbatt_raw_to_uv(chip,
- raw->last_good_ocv_raw);
+ raw->last_good_ocv_raw, is_pon_ocv);
chip->last_ocv_uv = raw->last_good_ocv_uv;
chip->last_ocv_temp = batt_temp;
chip->software_cc_uah = 0;
@@ -1042,7 +1042,7 @@
mutex_unlock(&chip->bms_output_lock);
if (chip->prev_last_good_ocv_raw == OCV_RAW_UNINITIALIZED) {
- convert_and_store_ocv(chip, raw, batt_temp);
+ convert_and_store_ocv(chip, raw, batt_temp, true);
pr_debug("PON_OCV_UV = %d, cc = %llx\n",
chip->last_ocv_uv, raw->cc);
warm_reset = qpnp_pon_is_warm_reset();
@@ -1078,7 +1078,7 @@
pr_debug("EOC Battery full ocv_reading = 0x%x\n",
chip->ocv_reading_at_100);
} else if (chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
- convert_and_store_ocv(chip, raw, batt_temp);
+ convert_and_store_ocv(chip, raw, batt_temp, false);
/* forget the old cc value upon ocv */
chip->last_cc_uah = INT_MIN;
} else {
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index bf294fc..6301724 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -650,24 +650,23 @@
return (batfet_closed_rt_sts & BAT_FET_ON_IRQ) ? 1 : 0;
}
-#define USB_VALID_BIT BIT(7)
static int
qpnp_chg_is_usb_chg_plugged_in(struct qpnp_chg_chip *chip)
{
- u8 usbin_valid_rt_sts;
+ u8 usb_chgpth_rt_sts;
int rc;
- rc = qpnp_chg_read(chip, &usbin_valid_rt_sts,
- chip->usb_chgpth_base + CHGR_STATUS , 1);
+ rc = qpnp_chg_read(chip, &usb_chgpth_rt_sts,
+ INT_RT_STS(chip->usb_chgpth_base), 1);
if (rc) {
pr_err("spmi read failed: addr=%03X, rc=%d\n",
- chip->usb_chgpth_base + CHGR_STATUS, rc);
+ INT_RT_STS(chip->usb_chgpth_base), rc);
return rc;
}
- pr_debug("chgr usb sts 0x%x\n", usbin_valid_rt_sts);
+ pr_debug("chgr usb sts 0x%x\n", usb_chgpth_rt_sts);
- return (usbin_valid_rt_sts & USB_VALID_BIT) ? 1 : 0;
+ return (usb_chgpth_rt_sts & USBIN_VALID_IRQ) ? 1 : 0;
}
static bool
@@ -686,10 +685,10 @@
return !!(buck_sts & IBAT_LOOP_IRQ);
}
-#define USB_VALID_MASK 0xC0
-#define USB_COARSE_DET 0x10
-#define USB_VALID_UVP_VALUE 0x00
-#define USB_VALID_OVP_VALUE 0x40
+#define USB_VALID_MASK 0xC0
+#define USB_VALID_IN_MASK BIT(7)
+#define USB_COARSE_DET 0x10
+#define USB_VALID_OVP_VALUE 0x40
static int
qpnp_chg_check_usb_coarse_det(struct qpnp_chg_chip *chip)
{
@@ -708,7 +707,8 @@
static int
qpnp_chg_check_usbin_health(struct qpnp_chg_chip *chip)
{
- u8 usbin_chg_rt_sts, usbin_health = 0;
+ u8 usbin_chg_rt_sts, usb_chgpth_rt_sts;
+ u8 usbin_health = 0;
int rc;
rc = qpnp_chg_read(chip, &usbin_chg_rt_sts,
@@ -720,13 +720,23 @@
return rc;
}
- pr_debug("chgr usb sts 0x%x\n", usbin_chg_rt_sts);
+ rc = qpnp_chg_read(chip, &usb_chgpth_rt_sts,
+ INT_RT_STS(chip->usb_chgpth_base) , 1);
+
+ if (rc) {
+ pr_err("spmi read failed: addr=%03X, rc=%d\n",
+ INT_RT_STS(chip->usb_chgpth_base), rc);
+ return rc;
+ }
+
+ pr_debug("chgr usb sts 0x%x, chgpth rt sts 0x%x\n",
+ usbin_chg_rt_sts, usb_chgpth_rt_sts);
if ((usbin_chg_rt_sts & USB_COARSE_DET) == USB_COARSE_DET) {
if ((usbin_chg_rt_sts & USB_VALID_MASK)
== USB_VALID_OVP_VALUE) {
usbin_health = USBIN_OVP;
pr_err("Over voltage charger inserted\n");
- } else if ((usbin_chg_rt_sts & USB_VALID_BIT) != 0) {
+ } else if ((usb_chgpth_rt_sts & USBIN_VALID_IRQ) != 0) {
usbin_health = USBIN_OK;
pr_debug("Valid charger inserted\n");
}
diff --git a/drivers/rtc/alarm.c b/drivers/rtc/alarm.c
index 06749b9..fb97329 100644
--- a/drivers/rtc/alarm.c
+++ b/drivers/rtc/alarm.c
@@ -71,9 +71,11 @@
static bool suspended;
static long power_on_alarm;
+static void alarm_shutdown(struct platform_device *dev);
void set_power_on_alarm(long secs)
{
power_on_alarm = secs;
+ alarm_shutdown(NULL);
}
diff --git a/drivers/video/msm/mdss/dsi_status_v2.c b/drivers/video/msm/mdss/dsi_status_v2.c
index d62ddf3..565401d 100644
--- a/drivers/video/msm/mdss/dsi_status_v2.c
+++ b/drivers/video/msm/mdss/dsi_status_v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -82,7 +82,19 @@
mdp3_session = pdsi_status->mfd->mdp.private1;
mutex_lock(&mdp3_session->lock);
- ret = ctrl_pdata->check_status(ctrl_pdata);
+ if (!mdp3_session->status) {
+ pr_info("display off already\n");
+ mutex_unlock(&mdp3_session->lock);
+ return;
+ }
+
+ if (mdp3_session->wait_for_dma_done)
+ ret = mdp3_session->wait_for_dma_done(mdp3_session);
+
+ if (!ret)
+ ret = ctrl_pdata->check_status(ctrl_pdata);
+ else
+ pr_err("wait_for_dma_done error\n");
mutex_unlock(&mdp3_session->lock);
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index da714ad..095a387 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -157,6 +157,7 @@
{
struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
schedule_work(&session->dma_done_work);
+ complete(&session->dma_completion);
}
void vsync_count_down(void *arg)
@@ -1036,7 +1037,8 @@
MDP_NOTIFY_FRAME_DONE);
}
}
-
+ mdp3_session->dma_active = 1;
+ init_completion(&mdp3_session->dma_completion);
mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED);
mdp3_bufq_push(&mdp3_session->bufq_out, data);
}
@@ -1130,6 +1132,8 @@
MDP_NOTIFY_FRAME_DONE);
}
}
+ mdp3_session->dma_active = 1;
+ init_completion(&mdp3_session->dma_completion);
mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED);
} else {
pr_debug("mdp3_ctrl_pan_display no memory, stop interface");
@@ -1751,6 +1755,23 @@
return rc;
}
+int mdp3_wait_for_dma_done(struct mdp3_session_data *session)
+{
+ int rc = 0;
+
+ if (session->dma_active) {
+ rc = wait_for_completion_timeout(&session->dma_completion,
+ KOFF_TIMEOUT);
+ if (rc > 0) {
+ session->dma_active = 0;
+ rc = 0;
+ } else if (rc == 0) {
+ rc = -ETIME;
+ }
+ }
+ return rc;
+}
+
int mdp3_ctrl_init(struct msm_fb_data_type *mfd)
{
struct device *dev = mfd->fbi->dev;
@@ -1825,6 +1846,9 @@
mdp3_session->vsync_timer.data = (u32)mdp3_session;
mdp3_session->vsync_period = 1000 / mfd->panel_info->mipi.frame_rate;
mfd->mdp.private1 = mdp3_session;
+ init_completion(&mdp3_session->dma_completion);
+ if (intf_type != MDP3_DMA_OUTPUT_SEL_DSI_VIDEO)
+ mdp3_session->wait_for_dma_done = mdp3_wait_for_dma_done;
rc = sysfs_create_group(&dev->kobj, &vsync_fs_attr_group);
if (rc) {
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
index cfad1d3..416b7c2 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -61,6 +61,10 @@
int vsync_enabled;
atomic_t vsync_countdown; /* Used to count down */
+
+ bool dma_active;
+ struct completion dma_completion;
+ int (*wait_for_dma_done)(struct mdp3_session_data *session);
};
int mdp3_ctrl_init(struct msm_fb_data_type *mfd);
diff --git a/drivers/video/msm/mdss/mdss_dsi_status.c b/drivers/video/msm/mdss/mdss_dsi_status.c
index f0c4f4c..fd7f3fd 100644
--- a/drivers/video/msm/mdss/mdss_dsi_status.c
+++ b/drivers/video/msm/mdss/mdss_dsi_status.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -86,6 +86,15 @@
mutex_lock(ctl->shared_lock);
mutex_lock(&mdp5_data->ov_lock);
+ if (pdsi_status->mfd->shutdown_pending) {
+ mutex_unlock(&mdp5_data->ov_lock);
+ if (ctl->shared_lock)
+ mutex_unlock(ctl->shared_lock);
+ pr_err("%s: DSI turning off, avoiding BTA status check\n",
+ __func__);
+ return;
+ }
+
/*
* For the command mode panels, we return pan display
* IOCTL on vsync interrupt. So, after vsync interrupt comes
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index cfa594c..bc4e1dc 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -1001,8 +1001,9 @@
writel_relaxed(1, offset + 16);
}
- mdata->nmax_concurrent_ad_hw = (mdata->mdp_rev <= MDSS_MDP_HW_REV_102) ?
- 1 : 2;
+ mdata->nmax_concurrent_ad_hw =
+ (mdata->mdp_rev < MDSS_MDP_HW_REV_103) ? 1 : 2;
+
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
pr_debug("MDP hw init done\n");
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index f3b7ce1..7dab8b2 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -543,7 +543,8 @@
struct mdss_mdp_pipe **left_plist, int left_cnt,
struct mdss_mdp_pipe **right_plist, int right_cnt);
int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
- struct mdss_mdp_perf_params *perf, struct mdss_mdp_img_rect *roi);
+ struct mdss_mdp_perf_params *perf, struct mdss_mdp_img_rect *roi,
+ bool apply_fudge);
int mdss_mdp_ctl_notify(struct mdss_mdp_ctl *ctl, int event);
void mdss_mdp_ctl_notifier_register(struct mdss_mdp_ctl *ctl,
struct notifier_block *notifier);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index fe42669..d807083 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -303,6 +303,7 @@
* @pipe: Source pipe struct containing updated pipe params
* @perf: Structure containing values that should be updated for
* performance tuning
+ * @apply_fudge: Boolean to determine if mdp clock fudge is applicable
*
* Function calculates the minimum required performance calculations in order
* to avoid MDP underflow. The calculations are based on the way MDP
@@ -310,7 +311,8 @@
* (MDP clock requirement) based on frame size and scaling requirements.
*/
int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
- struct mdss_mdp_perf_params *perf, struct mdss_mdp_img_rect *roi)
+ struct mdss_mdp_perf_params *perf, struct mdss_mdp_img_rect *roi,
+ bool apply_fudge)
{
struct mdss_mdp_mixer *mixer;
int fps = DEFAULT_FRAME_RATE;
@@ -384,7 +386,10 @@
perf->bw_overlap = (quota / dst.h) * v_total;
}
- perf->mdp_clk_rate = mdss_mdp_clk_fudge_factor(mixer, rate);
+ if (apply_fudge)
+ perf->mdp_clk_rate = mdss_mdp_clk_fudge_factor(mixer, rate);
+ else
+ perf->mdp_clk_rate = rate;
prefill_params.smp_bytes = mdss_mdp_smp_get_size(pipe);
prefill_params.xres = xres;
@@ -440,6 +445,8 @@
u64 bw_overlap[MDSS_MDP_MAX_STAGE] = { 0 };
u32 v_region[MDSS_MDP_MAX_STAGE * 2] = { 0 };
u32 prefill_bytes = 0;
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+ bool apply_fudge = true;
BUG_ON(num_pipes > MDSS_MDP_MAX_STAGE);
@@ -469,13 +476,36 @@
memset(bw_overlap, 0, sizeof(u64) * MDSS_MDP_MAX_STAGE);
memset(v_region, 0, sizeof(u32) * MDSS_MDP_MAX_STAGE * 2);
+ /*
+ * Apply this logic only for 8x26 to reduce clock rate
+ * for single video playback use case
+ */
+ if (IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev, MDSS_MDP_HW_REV_101)
+ && mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
+ u32 npipes = 0;
+ for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) {
+ pipe = mixer->stage_pipe[i];
+ if (pipe) {
+ if (npipes) {
+ apply_fudge = true;
+ break;
+ }
+ npipes++;
+ apply_fudge = !(pipe->src_fmt->is_yuv)
+ || !(pipe->flags
+ & MDP_SOURCE_ROTATED_90);
+ }
+ }
+ }
+
for (i = 0; i < num_pipes; i++) {
struct mdss_mdp_perf_params tmp;
pipe = pipe_list[i];
if (pipe == NULL)
continue;
- if (mdss_mdp_perf_calc_pipe(pipe, &tmp, &mixer->roi))
+ if (mdss_mdp_perf_calc_pipe(pipe, &tmp, &mixer->roi,
+ apply_fudge))
continue;
prefill_bytes += tmp.prefill_bytes;
bw_overlap[i] = tmp.bw_overlap;
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index bff56d2..4b9ea20 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -21,10 +21,6 @@
#define ENHIST_LUT_ENTRIES 256
#define HIST_V_SIZE 256
-#define MDSS_MDP_HW_REV_100 0x10000000
-#define MDSS_MDP_HW_REV_102 0x10020000
-#define MDSS_MDP_HW_REV_103 0x10030000
-
#define MDSS_MDP_FETCH_CONFIG_RESET_VALUE 0x00000087
#define MDSS_REG_HW_VERSION 0x0
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 34cfe23..8acbd35 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -268,7 +268,7 @@
int rc;
for (;;) {
- rc = mdss_mdp_perf_calc_pipe(pipe, &perf, NULL);
+ rc = mdss_mdp_perf_calc_pipe(pipe, &perf, NULL, true);
if (!rc && (perf.mdp_clk_rate <= mdata->max_mdp_clk_rate))
break;
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index bff056d..e53c350 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -197,6 +197,12 @@
void *handler_priv;
};
+enum dev_state {
+ DEV_SUSPENDING = 1,
+ DEV_SUSPENDED,
+ DEV_RESUMED,
+};
+
struct mmc_host {
struct device *parent;
struct device class_dev;
@@ -421,6 +427,7 @@
struct delayed_work work;
enum mmc_load state;
} clk_scaling;
+ enum dev_state dev_status;
unsigned long private[0] ____cacheline_aligned;
};
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 08ca341..65a3fe1 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -160,6 +160,11 @@
*/
#define SDHCI_QUIRK2_DIVIDE_TOUT_BY_4 (1 << 9)
+/*
+ * Some SDHC controllers are unable to handle data-end bit error in
+ * 1-bit mode of SDIO.
+ */
+#define SDHCI_QUIRK2_IGN_DATA_END_BIT_ERROR (1<<9)
int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
@@ -252,6 +257,9 @@
struct mutex ios_mutex;
enum sdhci_power_policy power_policy;
+ bool irq_enabled; /* host irq status flag */
+ bool async_int_supp; /* async support to rxv int, when clks are off */
+ bool disable_sdio_irq_deferred; /* status of disabling sdio irq */
u32 auto_cmd_err_sts;
unsigned long private[0] ____cacheline_aligned;
};
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index e332368..3ec92e6 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -85,6 +85,30 @@
#define MDP_IMGTYPE2_START 0x10000
#define MSMFB_DRIVER_VERSION 0xF9E8D701
+/* HW Revisions for different MDSS targets */
+#define MDSS_GET_MAJOR(rev) ((rev) >> 28)
+#define MDSS_GET_MINOR(rev) (((rev) >> 16) & 0xFFF)
+#define MDSS_GET_STEP(rev) ((rev) & 0xFFFF)
+#define MDSS_GET_MAJOR_MINOR(rev) ((rev) >> 16)
+
+#define IS_MDSS_MAJOR_MINOR_SAME(rev1, rev2) \
+ (MDSS_GET_MAJOR_MINOR((rev1)) == MDSS_GET_MAJOR_MINOR((rev2)))
+
+#define MDSS_MDP_REV(major, minor, step) \
+ ((((major) & 0x000F) << 28) | \
+ (((minor) & 0x0FFF) << 16) | \
+ ((step) & 0xFFFF))
+
+#define MDSS_MDP_HW_REV_100 MDSS_MDP_REV(1, 0, 0) /* 8974 v1.0 */
+#define MDSS_MDP_HW_REV_101 MDSS_MDP_REV(1, 1, 0) /* 8x26 v1.0 */
+#define MDSS_MDP_HW_REV_101_1 MDSS_MDP_REV(1, 1, 1) /* 8x26 v2.0, 8926 v1.0 */
+#define MDSS_MDP_HW_REV_101_2 MDSS_MDP_REV(1, 1, 2) /* 8926 v2.0 */
+#define MDSS_MDP_HW_REV_102 MDSS_MDP_REV(1, 2, 0) /* 8974 v2.0 */
+#define MDSS_MDP_HW_REV_102_1 MDSS_MDP_REV(1, 2, 1) /* 8974 v3.0 (Pro) */
+#define MDSS_MDP_HW_REV_103 MDSS_MDP_REV(1, 3, 0) /* 8084 v1.0 */
+#define MDSS_MDP_HW_REV_103_1 MDSS_MDP_REV(1, 3, 1) /* 8084 v1.1 */
+#define MDSS_MDP_HW_REV_200 MDSS_MDP_REV(2, 0, 0) /* 8092 v1.0 */
+
enum {
NOTIFY_UPDATE_START,
NOTIFY_UPDATE_STOP,
diff --git a/include/linux/qpnp-revid.h b/include/linux/qpnp-revid.h
index 3cf9f1c..3d271f0 100644
--- a/include/linux/qpnp-revid.h
+++ b/include/linux/qpnp-revid.h
@@ -13,6 +13,13 @@
#ifndef __QPNP_REVID
#define __QPNP_REVID
+#define PM8226_V2P2_REV1 0x00
+#define PM8226_V2P2_REV2 0x00
+#define PM8226_V2P2_REV3 0x02
+#define PM8226_V2P2_REV4 0x02
+#define PM8226_V2P2_TYPE 0x51
+#define PM8226_V2P2_SUBTYPE 0x04
+
#define PM8226_V2P1_REV1 0x00
#define PM8226_V2P1_REV2 0x00
#define PM8226_V2P1_REV3 0x01
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 13eb461..7ba4148 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -20,6 +20,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
+#include <linux/qpnp-revid.h>
/**
* enum qpnp_vadc_channels - QPNP AMUX arbiter channels
*/
@@ -1002,15 +1003,27 @@
* @chan_prop - Represent the channel properties of the ADC.
*/
struct qpnp_adc_amux_properties {
- uint32_t amux_channel;
- uint32_t decimation;
- uint32_t mode_sel;
- uint32_t hw_settle_time;
- uint32_t fast_avg_setup;
- enum qpnp_vadc_trigger trigger_channel;
+ uint32_t amux_channel;
+ uint32_t decimation;
+ uint32_t mode_sel;
+ uint32_t hw_settle_time;
+ uint32_t fast_avg_setup;
+ enum qpnp_vadc_trigger trigger_channel;
struct qpnp_vadc_chan_properties chan_prop[0];
};
+/* SW index's for PMIC type and version used by QPNP VADC and IADC */
+#define QPNP_REV_ID_8941_3_1 1
+#define QPNP_REV_ID_8026_1_0 2
+#define QPNP_REV_ID_8026_2_0 3
+#define QPNP_REV_ID_8110_1_0 4
+#define QPNP_REV_ID_8026_2_1 5
+#define QPNP_REV_ID_8110_2_0 6
+#define QPNP_REV_ID_8026_2_2 7
+#define QPNP_REV_ID_8941_3_0 8
+#define QPNP_REV_ID_8941_2_0 9
+
+
/* Public API */
#if defined(CONFIG_SENSORS_QPNP_ADC_VOLTAGE) \
|| defined(CONFIG_SENSORS_QPNP_ADC_VOLTAGE_MODULE)
@@ -1366,9 +1379,16 @@
* qpnp_vadc_sns_comp_result() - Compensate vbatt readings based on temperature
* @dev: Structure device for qpnp vadc
* @result: Voltage in uV that needs compensation.
+ * @is_pon_ocv: Whether the reading is from a power on OCV or not
*/
int32_t qpnp_vbat_sns_comp_result(struct qpnp_vadc_chip *dev,
- int64_t *result);
+ int64_t *result, bool is_pon_ocv);
+/**
+ * qpnp_adc_get_revid_version() - Obtain the PMIC number and revision.
+ * @dev: Structure device node.
+ * returns internal mapped PMIC number and revision id.
+ */
+int qpnp_adc_get_revid_version(struct device *dev);
#else
static inline int32_t qpnp_vadc_read(struct qpnp_vadc_chip *dev,
uint32_t channel,
@@ -1482,6 +1502,8 @@
static inline int32_t qpnp_vbat_sns_comp_result(struct qpnp_vadc_chip *dev,
int64_t *result)
{ return -ENXIO; }
+static inline int qpnp_adc_get_revid_version(struct device *dev)
+{ return -ENXIO; }
#endif
/* Public API */
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 700d2ae..f320017 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -384,7 +384,7 @@
void tracing_off(void)
{
if (global_trace.buffer)
- ring_buffer_record_on(global_trace.buffer);
+ ring_buffer_record_off(global_trace.buffer);
/*
* This flag is only looked at when buffers haven't been
* allocated yet. We don't really care about the race
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index b28b7eb..c868a74 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3816,6 +3816,11 @@
struct lsm_network_audit net = {0,};
u32 tsid = task_sid(task);
+ if (unlikely(!sksec)) {
+ pr_warn("SELinux: sksec is NULL, socket is already freed\n");
+ return -EINVAL;
+ }
+
if (sksec->sid == SECINITSID_KERNEL)
return 0;
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index b72590f..7b1a04e 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -6797,18 +6797,21 @@
snd_soc_card_change_online_state(codec->card, 1);
mutex_lock(&codec->mutex);
- if (codec->reg_def_copy) {
- pr_debug("%s: Update ASOC cache", __func__);
- kfree(codec->reg_cache);
- codec->reg_cache = kmemdup(codec->reg_def_copy,
- codec->reg_size, GFP_KERNEL);
- }
+
+ taiko_update_reg_defaults(codec);
+ if (wcd9xxx->mclk_rate == TAIKO_MCLK_CLK_12P288MHZ)
+ snd_soc_update_bits(codec, TAIKO_A_CHIP_CTL, 0x06, 0x0);
+ else if (wcd9xxx->mclk_rate == TAIKO_MCLK_CLK_9P6MHZ)
+ snd_soc_update_bits(codec, TAIKO_A_CHIP_CTL, 0x06, 0x2);
+ taiko_codec_init_reg(codec);
if (spkr_drv_wrnd == 1)
snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_EN, 0x80, 0x80);
- taiko_update_reg_defaults(codec);
- taiko_codec_init_reg(codec);
+ codec->cache_sync = true;
+ snd_soc_cache_sync(codec);
+ codec->cache_sync = false;
+
ret = taiko_handle_pdata(taiko);
if (IS_ERR_VALUE(ret))
pr_err("%s: bad pdata\n", __func__);