Merge "ASoC: msm: Fix crash during FM recording." into msm-3.4
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
index 35385d3..4129f7f 100644
--- a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
@@ -18,7 +18,11 @@
- qcom,vdd-mem-upper-bound: The upper bound value of mem voltage in uV
- qcom,vdd-mem-lower-bound: The lower bound value of mem voltage in uV
- qcom,vdd-dig-upper-bound: The upper bound value of dig voltage in uV
+ or an RBCPR (Rapid Bridge Core Power Reduction)
+ corner voltage.
- qcom,vdd-dig-lower-bound: The lower bound value of dig voltage in uV
+ or an RBCPR (Rapid Bridge Core Power Reduction)
+ corner voltage.
- qcom,latency-us: The latency in handling the interrupt if this level was
chosen, in uSec
- qcom,ss-power: The steady state power expelled when the processor is in this
@@ -37,8 +41,8 @@
qcom,l2 = <3>; /* ACTIVE */
qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
- qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
- qcom,vdd-dig-lower-bound = <950000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <5>; /* MAX */
+ qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
qcom,latency-us = <100>;
qcom,ss-power = <650>;
qcom,energy-overhead = <801>;
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt b/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
index 9ff43a1..b16d40f 100644
--- a/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
@@ -13,19 +13,20 @@
- compatible: "qcom,lpm-resources"
- reg: The numeric level id
-- qcom,name: The name of the low power resource.
-- qcom,type: The string represeting the type of resource used
- like smps or pxo.
+- qcom,name: The name of the low power resource represented
+ as a string.
+- qcom,type: The type of resource used like smps or pxo
+ represented as a hex value.
- qcom,id: The id representing a device within a resource type.
- qcom,key: The key is the specific attribute of the resource being
- monitored.
+ monitored represented as a hex value.
Example:
qcom,lpm-resources@0 {
reg = <0x0>;
qcom,name = "vdd-dig";
- qcom,type = "smpb\0";
+ qcom,type = <0x62706d73>; /* "smpb" */
qcom,id = <0x02>;
- qcom,key = "uv\0\0";
+ qcom,key = <0x6e726f63>; /* "corn" */
};
diff --git a/Documentation/devicetree/bindings/cache/msm_cache_erp.txt b/Documentation/devicetree/bindings/cache/msm_cache_erp.txt
new file mode 100644
index 0000000..400b299
--- /dev/null
+++ b/Documentation/devicetree/bindings/cache/msm_cache_erp.txt
@@ -0,0 +1,16 @@
+* Qualcomm Krait L1 / L2 cache error reporting driver
+
+Required properties:
+- compatible: Should be "qcom,cache_erp"
+- interrupts: Should contain the L1/CPU error interrupt number and
+ the L2 cache interrupt number
+- interrupt-names: Should contain the interrupt names "l1_irq" and
+ "l2_irq"
+
+Example:
+ qcom,cache_erp {
+ compatible = "qcom,cache_erp";
+ interrupts = <1 9 0>, <0 2 0>;
+ interrupt-names = "l1_irq", "l2_irq";
+ };
+
diff --git a/Documentation/devicetree/bindings/mmc/msm_sdcc.txt b/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
index 35ac0ec..a8de90f 100644
--- a/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
+++ b/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
@@ -35,6 +35,15 @@
- qcom,sdcc-<supply>-current_level - specifies load levels for supply in lpm or
high power mode (hpm). Should be specified in pairs (lpm, hpm), units uA.
+ - gpios - specifies gpios assigned for sdcc slot.
+ - qcom,sdcc-gpio-names - a list of strings that map in order to the list of gpios
+ A slot has either gpios or dedicated tlmm pins as represented below.
+ - qcom,sdcc-pad-pull-on - Active pull configuration for sdc tlmm pins
+ - qcom,sdcc-pad-pull-off - Suspend pull configuration for sdc tlmm pins.
+ - qcom,sdcc-pad-drv-on - Active drive strength configuration for sdc tlmm pins.
+ - qcom,sdcc-pad-drv-off - Suspend drive strength configuration for sdc tlmm pins.
+ Tlmm pins are specified as <clk cmd data>
+
Example:
qcom,sdcc@f9600000 {
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index b6086e7..16a5c77 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -18,6 +18,12 @@
- compatible : "qcom,msm-pcm-lpa"
+* msm-compr-dsp
+
+Required properties:
+
+ - compatible : "qcom,msm-compr-dsp"
+
* msm-voip-dsp
Required properties:
@@ -95,6 +101,10 @@
compatible = "qcom,msm-pcm-lpa";
};
+ qcom,msm-compr-dsp {
+ compatible = "qcom,msm-compr-dsp";
+ };
+
qcom,msm-voip-dsp {
compatible = "qcom,msm-voip-dsp";
};
@@ -119,12 +129,12 @@
qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>;
qcom,msm-auxpcm-rx {
- qcom,msm-auxpcm-dev-id = <4106>;
+ qcom,msm-auxpcm-dev-id = <4106>;
compatible = "qcom,msm-auxpcm-dev";
};
qcom,msm-auxpcm-tx {
- qcom,msm-auxpcm-dev-id = <4107>;
+ qcom,msm-auxpcm-dev-id = <4107>;
compatible = "qcom,msm-auxpcm-dev";
};
};
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index f462a1e..6737e89 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -315,6 +315,23 @@
status = "disabled";
};
};
+
+ qcom,pm8941_rtc {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-rtc";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ qcom,qpnp-rtc-write = <0>;
+ qcom,qpnp-rtc-alarm-pwrup = <0>;
+
+ qcom,pm8941_rtc_rw@6000 {
+ reg = <0x6000 0x100>;
+ };
+ qcom,pm8941_rtc_alarm@6100 {
+ reg = <0x6100 0x100>;
+ interrupts = <0x0 0x61 0x1>;
+ };
+ };
};
qcom,pm8941@1 {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 2eb8216..edb86be 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -76,7 +76,7 @@
};
qcom,sdcc@f9824000 {
- cell-index = <1>;
+ cell-index = <1>; /* SDC1 eMMC slot */
compatible = "qcom,msm-sdcc";
reg = <0xf9824000 0x1000>;
interrupts = <0 123 0>;
@@ -90,6 +90,11 @@
qcom,sdcc-vdd-io-voltage_level = <1800000 1800000>;
qcom,sdcc-vdd-io-current_level = <250 154000>;
+ qcom,sdcc-pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,sdcc-pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,sdcc-pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+ qcom,sdcc-pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
qcom,sdcc-sup-voltages = <2950 2950>;
qcom,sdcc-bus-width = <8>;
@@ -98,7 +103,7 @@
};
qcom,sdcc@f98a4000 {
- cell-index = <2>;
+ cell-index = <2>; /* SDC2 SD card slot */
compatible = "qcom,msm-sdcc";
reg = <0xf98a4000 0x1000>;
interrupts = <0 125 0>;
@@ -113,6 +118,11 @@
qcom,sdcc-vdd-io-voltage_level = <1800000 2950000>;
qcom,sdcc-vdd-io-current_level = <6 22000>;
+ qcom,sdcc-pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,sdcc-pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,sdcc-pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+ qcom,sdcc-pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
qcom,sdcc-sup-voltages = <2950 2950>;
qcom,sdcc-bus-width = <4>;
@@ -122,11 +132,19 @@
};
qcom,sdcc@f9864000 {
- cell-index = <3>;
+ cell-index = <3>; /* SDC3 SDIO slot */
compatible = "qcom,msm-sdcc";
reg = <0xf9864000 0x1000>;
interrupts = <0 127 0>;
+ gpios = <&msmgpio 40 0>, /* CLK */
+ <&msmgpio 39 0>, /* CMD */
+ <&msmgpio 38 0>, /* DATA0 */
+ <&msmgpio 37 0>, /* DATA1 */
+ <&msmgpio 36 0>, /* DATA2 */
+ <&msmgpio 35 0>; /* DATA3 */
+ qcom,sdcc-gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
+
qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000>;
qcom,sdcc-sup-voltages = <1800 1800>;
qcom,sdcc-bus-width = <4>;
@@ -135,11 +153,19 @@
};
qcom,sdcc@f98e4000 {
- cell-index = <4>;
+ cell-index = <4>; /* SDC4 SDIO slot */
compatible = "qcom,msm-sdcc";
reg = <0xf98e4000 0x1000>;
interrupts = <0 129 0>;
+ gpios = <&msmgpio 93 0>, /* CLK */
+ <&msmgpio 91 0>, /* CMD */
+ <&msmgpio 96 0>, /* DATA0 */
+ <&msmgpio 95 0>, /* DATA1 */
+ <&msmgpio 94 0>, /* DATA2 */
+ <&msmgpio 92 0>; /* DATA3 */
+ qcom,sdcc-gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
+
qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000>;
qcom,sdcc-sup-voltages = <1800 1800>;
qcom,sdcc-bus-width = <4>;
@@ -352,6 +378,10 @@
compatible = "qcom,msm-pcm-lpa";
};
+ qcom,msm-compr-dsp {
+ compatible = "qcom,msm-compr-dsp";
+ };
+
qcom,msm-voip-dsp {
compatible = "qcom,msm-voip-dsp";
};
@@ -449,7 +479,7 @@
partition@E0000 {
reg = <0x120000 0x20000>;
- qcom,ocmem-part-name = "blast";
+ qcom,ocmem-part-name = "other_os";
qcom,ocmem-part-min = <0x20000>;
};
diff --git a/arch/arm/boot/dts/msm8974_pm.dtsi b/arch/arm/boot/dts/msm8974_pm.dtsi
index 6f12e31c..aab2722 100644
--- a/arch/arm/boot/dts/msm8974_pm.dtsi
+++ b/arch/arm/boot/dts/msm8974_pm.dtsi
@@ -140,25 +140,25 @@
qcom,lpm-resources@0 {
reg = <0x0>;
qcom,name = "vdd-dig";
- qcom,type = "smpb\0";
+ qcom,type = <0x62706d73>; /* "smpb" */
qcom,id = <0x02>;
- qcom,key = "uv\0\0";
+ qcom,key = <0x6e726f63>; /* "corn" */
};
qcom,lpm-resources@1 {
reg = <0x1>;
qcom,name = "vdd-mem";
- qcom,type = "smpb\0";
+ qcom,type = <0x62706d73>; /* "smpb" */
qcom,id = <0x01>;
- qcom,key = "uv\0\0";
+ qcom,key = <0x7675>; /* "uv" */
};
qcom,lpm-resources@2 {
reg = <0x2>;
qcom,name = "pxo";
- qcom,type = "clk0\0";
+ qcom,type = <0x306b6c63>; /* "clk0" */
qcom,id = <0x00>;
- qcom,key = "Enab";
+ qcom,key = <0x62616e45>; /* "Enab" */
};
};
@@ -174,8 +174,8 @@
qcom,l2 = <3>; /* ACTIVE */
qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
- qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
- qcom,vdd-dig-lower-bound = <950000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <5>; /* MAX */
+ qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
qcom,latency-us = <100>;
qcom,ss-power = <650>;
qcom,energy-overhead = <801>;
@@ -189,8 +189,8 @@
qcom,l2 = <3>; /* ACTIVE */
qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
- qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
- qcom,vdd-dig-lower-bound = <950000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <5>; /* MAX */
+ qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
qcom,latency-us = <2000>;
qcom,ss-power = <200>;
qcom,energy-overhead = <576000>;
@@ -204,8 +204,8 @@
qcom,l2 = <1>; /* GDHS */
qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
- qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
- qcom,vdd-dig-lower-bound = <950000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <5>; /* MAX */
+ qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
qcom,latency-us = <8500>;
qcom,ss-power = <51>;
qcom,energy-overhead = <1122000>;
@@ -219,8 +219,8 @@
qcom,l2 = <0>; /* OFF */
qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
- qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
- qcom,vdd-dig-lower-bound = <950000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <5>; /* MAX */
+ qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
qcom,latency-us = <9000>;
qcom,ss-power = <51>;
qcom,energy-overhead = <1130300>;
@@ -234,8 +234,8 @@
qcom,l2 = <0>; /* OFF */
qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
qcom,vdd-mem-lower-bound = <750000>; /* RETENTION HIGH */
- qcom,vdd-dig-upper-bound = <950000>; /* ACTIVE */
- qcom,vdd-dig-lower-bound = <750000>; /* RETENTION HIGH */
+ qcom,vdd-dig-upper-bound = <3>; /* ACTIVE */
+ qcom,vdd-dig-lower-bound = <2>; /* RETENTION HIGH */
qcom,latency-us = <10000>;
qcom,ss-power = <51>;
qcom,energy-overhead = <1130300>;
@@ -249,8 +249,8 @@
qcom,l2 = <1>; /* GDHS */
qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
- qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
- qcom,vdd-dig-lower-bound = <950000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <5>; /* MAX */
+ qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
qcom,latency-us = <12000>;
qcom,ss-power = <14>;
qcom,energy-overhead = <2205900>;
@@ -264,8 +264,8 @@
qcom,l2 = <0>; /* OFF */
qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
- qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
- qcom,vdd-dig-lower-bound = <950000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <5>; /* MAX */
+ qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
qcom,latency-us = <18000>;
qcom,ss-power = <12>;
qcom,energy-overhead = <2364250>;
@@ -279,8 +279,8 @@
qcom,l2 = <0>; /* OFF */
qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
qcom,vdd-mem-lower-bound = <750000>; /* RETENTION HIGH */
- qcom,vdd-dig-upper-bound = <950000>; /* ACTIVE */
- qcom,vdd-dig-lower-bound = <750000>; /* RETIONTION HIGH */
+ qcom,vdd-dig-upper-bound = <3>; /* ACTIVE */
+ qcom,vdd-dig-lower-bound = <2>; /* RETIONTION HIGH */
qcom,latency-us = <23500>;
qcom,ss-power = <10>;
qcom,energy-overhead = <2667000>;
@@ -294,8 +294,8 @@
qcom,l2 = <0>; /* OFF */
qcom,vdd-mem-upper-bound = <750000>; /* RETENTION HIGH */
qcom,vdd-mem-lower-bound = <750000>; /* RETENTION LOW */
- qcom,vdd-dig-upper-bound = <750000>; /* RETENTION HIGH */
- qcom,vdd-dig-lower-bound = <500000>; /* RETENTION LOW */
+ qcom,vdd-dig-upper-bound = <2>; /* RETENTION HIGH */
+ qcom,vdd-dig-lower-bound = <0>; /* RETENTION LOW */
qcom,latency-us = <29700>;
qcom,ss-power = <5>;
qcom,energy-overhead = <2867000>;
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 88c4862..bbd6c63 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -47,6 +47,8 @@
#include <asm/hardware/gic.h>
#include <asm/system.h>
+#include <mach/socinfo.h>
+
union gic_base {
void __iomem *common_base;
void __percpu __iomem **percpu_base;
@@ -56,6 +58,7 @@
unsigned int irq_offset;
union gic_base dist_base;
union gic_base cpu_base;
+ bool need_access_lock;
#ifdef CONFIG_CPU_PM
u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)];
@@ -207,14 +210,8 @@
{
unsigned int i;
void __iomem *base = gic_data_dist_base(gic);
-#ifdef CONFIG_ARCH_MSM8625
- unsigned long flags;
-#endif
for (i = 0; i * 32 < gic->max_irq; i++) {
-#ifdef CONFIG_ARCH_MSM8625
- raw_spin_lock_irqsave(&irq_controller_lock, flags);
-#endif
gic->enabled_irqs[i]
= readl_relaxed(base + GIC_DIST_ENABLE_SET + i * 4);
/* disable all of them */
@@ -222,9 +219,6 @@
/* enable the wakeup set */
writel_relaxed(gic->wakeup_irqs[i],
base + GIC_DIST_ENABLE_SET + i * 4);
-#ifdef CONFIG_ARCH_MSM8625
- raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
-#endif
}
mb();
return 0;
@@ -305,18 +299,19 @@
static void gic_eoi_irq(struct irq_data *d)
{
+ struct gic_chip_data *gic = irq_data_get_irq_chip_data(d);
+
if (gic_arch_extn.irq_eoi) {
raw_spin_lock(&irq_controller_lock);
gic_arch_extn.irq_eoi(d);
raw_spin_unlock(&irq_controller_lock);
}
-#ifdef CONFIG_ARCH_MSM8625
- raw_spin_lock(&irq_controller_lock);
-#endif
+
+ if (gic->need_access_lock)
+ raw_spin_lock(&irq_controller_lock);
writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
-#ifdef CONFIG_ARCH_MSM8625
- raw_spin_unlock(&irq_controller_lock);
-#endif
+ if (gic->need_access_lock)
+ raw_spin_unlock(&irq_controller_lock);
}
static int gic_set_type(struct irq_data *d, unsigned int type)
@@ -435,13 +430,11 @@
void __iomem *cpu_base = gic_data_cpu_base(gic);
do {
-#ifdef CONFIG_ARCH_MSM8625
- raw_spin_lock(&irq_controller_lock);
-#endif
+ if (gic->need_access_lock)
+ raw_spin_lock(&irq_controller_lock);
irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
-#ifdef CONFIG_ARCH_MSM8625
- raw_spin_unlock(&irq_controller_lock);
-#endif
+ if (gic->need_access_lock)
+ raw_spin_unlock(&irq_controller_lock);
irqnr = irqstat & ~0x1c00;
if (likely(irqnr > 15 && irqnr < 1021)) {
@@ -450,13 +443,11 @@
continue;
}
if (irqnr < 16) {
-#ifdef CONFIG_ARCH_MSM8625
- raw_spin_lock(&irq_controller_lock);
-#endif
+ if (gic->need_access_lock)
+ raw_spin_lock(&irq_controller_lock);
writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
-#ifdef CONFIG_ARCH_MSM8625
- raw_spin_unlock(&irq_controller_lock);
-#endif
+ if (gic->need_access_lock)
+ raw_spin_unlock(&irq_controller_lock);
#ifdef CONFIG_SMP
handle_IPI(irqnr, regs);
#endif
@@ -583,9 +574,8 @@
* Deal with the banked PPI and SGI interrupts - disable all
* PPI interrupts, ensure all SGI interrupts are enabled.
*/
-#ifdef CONFIG_ARCH_MSM8625
- raw_spin_lock(&irq_controller_lock);
-#endif
+ if (gic->need_access_lock)
+ raw_spin_lock(&irq_controller_lock);
writel_relaxed(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
writel_relaxed(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
@@ -605,9 +595,8 @@
writel_relaxed(0xF, base + GIC_CPU_CTRL);
else
writel_relaxed(1, base + GIC_CPU_CTRL);
-#ifdef CONFIG_ARCH_MSM8625
- raw_spin_unlock(&irq_controller_lock);
-#endif
+ if (gic->need_access_lock)
+ raw_spin_unlock(&irq_controller_lock);
mb();
}
@@ -883,6 +872,10 @@
BUG_ON(gic_nr >= MAX_GIC_NR);
gic = &gic_data[gic_nr];
+ if (cpu_is_msm8625() &&
+ (SOCINFO_VERSION_MAJOR(socinfo_get_version()) <= 1))
+ gic->need_access_lock = true;
+
#ifdef CONFIG_GIC_NON_BANKED
if (percpu_offset) { /* Frankein-GIC without banked registers... */
unsigned int cpu;
@@ -967,9 +960,8 @@
int cpu;
unsigned long sgir;
unsigned long map = 0;
-#ifdef CONFIG_ARCH_MSM8625
- unsigned long flags;
-#endif
+ unsigned long flags = 0;
+ struct gic_chip_data *gic = &gic_data[0];
/* Convert our logical CPU mask into a physical one. */
for_each_cpu(cpu, mask)
@@ -985,16 +977,12 @@
*/
dsb();
-#ifdef CONFIG_ARCH_MSM8625
- raw_spin_lock_irqsave(&irq_controller_lock, flags);
-#endif
+ if (gic->need_access_lock)
+ raw_spin_lock_irqsave(&irq_controller_lock, flags);
/* this always happens on GIC0 */
-
- writel_relaxed(sgir,
- gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
-#ifdef CONFIG_ARCH_MSM8625
- raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
-#endif
+ writel_relaxed(sgir, gic_data_dist_base(gic) + GIC_DIST_SOFTINT);
+ if (gic->need_access_lock)
+ raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
mb();
}
#endif
@@ -1151,7 +1139,7 @@
}
#endif
-void msm_gic_save(bool modem_wake, int from_idle)
+void msm_gic_save(void)
{
unsigned int i;
struct gic_chip_data *gic = &gic_data[0];
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h
index 5078148..ad12bcd 100644
--- a/arch/arm/include/asm/hardware/gic.h
+++ b/arch/arm/include/asm/hardware/gic.h
@@ -60,7 +60,7 @@
}
void gic_set_irq_secure(unsigned int irq);
-void msm_gic_save(bool modem_wake, int from_idle);
+void msm_gic_save(void);
void msm_gic_restore(void);
void core1_gic_configure_and_raise(void);
#endif
diff --git a/arch/arm/include/asm/spinlock.h b/arch/arm/include/asm/spinlock.h
index 582c9b3..94aa75e 100644
--- a/arch/arm/include/asm/spinlock.h
+++ b/arch/arm/include/asm/spinlock.h
@@ -7,6 +7,8 @@
#include <asm/processor.h>
+extern int msm_krait_need_wfe_fixup;
+
/*
* sev and wfe are ARMv6K extensions. Uniprocessor ARMv6 may not have the K
* extensions, so when running on UP, we have to patch these instructions away.
@@ -21,25 +23,42 @@
#ifdef CONFIG_THUMB2_KERNEL
#define SEV ALT_SMP("sev.w", "nop.w")
/*
- * For Thumb-2, special care is needed to ensure that the conditional WFE
- * instruction really does assemble to exactly 4 bytes (as required by
- * the SMP_ON_UP fixup code). By itself "wfene" might cause the
- * assembler to insert a extra (16-bit) IT instruction, depending on the
- * presence or absence of neighbouring conditional instructions.
- *
- * To avoid this unpredictableness, an approprite IT is inserted explicitly:
- * the assembler won't change IT instructions which are explicitly present
- * in the input.
+ * Both instructions given to the ALT_SMP macro need to be the same size, to
+ * allow the SMP_ON_UP fixups to function correctly. Hence the explicit encoding
+ * specifications.
*/
-#define WFE(cond) ALT_SMP( \
- "it " cond "\n\t" \
- "wfe" cond ".n", \
- \
+#define WFE() ALT_SMP( \
+ "wfe.w", \
"nop.w" \
)
#else
#define SEV ALT_SMP("sev", "nop")
-#define WFE(cond) ALT_SMP("wfe" cond, "nop")
+#define WFE() ALT_SMP("wfe", "nop")
+#endif
+
+/*
+ * The fixup involves disabling interrupts during execution of the WFE
+ * instruction. This could potentially lead to deadlock if a thread is trying
+ * to acquire a spinlock which is being released from an interrupt context.
+ */
+#ifdef CONFIG_MSM_KRAIT_WFE_FIXUP
+#define WFE_SAFE(fixup, tmp) \
+" mrs " tmp ", cpsr\n" \
+" cmp " fixup ", #0\n" \
+" wfeeq\n" \
+" beq 10f\n" \
+" cpsid if\n" \
+" mrc p15, 7, " fixup ", c15, c0, 5\n" \
+" bic " fixup ", " fixup ", #0x10000\n" \
+" mcr p15, 7, " fixup ", c15, c0, 5\n" \
+" isb\n" \
+" wfe\n" \
+" orr " fixup ", " fixup ", #0x10000\n" \
+" mcr p15, 7, " fixup ", c15, c0, 5\n" \
+" isb\n" \
+"10: msr cpsr_cf, " tmp "\n"
+#else
+#define WFE_SAFE(fixup, tmp) " wfe\n"
#endif
static inline void dsb_sev(void)
@@ -79,17 +98,19 @@
static inline void arch_spin_lock(arch_spinlock_t *lock)
{
- unsigned long tmp;
+ unsigned long tmp, fixup = msm_krait_need_wfe_fixup;
__asm__ __volatile__(
-"1: ldrex %0, [%1]\n"
-" teq %0, #0\n"
- WFE("ne")
-" strexeq %0, %2, [%1]\n"
-" teqeq %0, #0\n"
+"1: ldrex %[tmp], [%[lock]]\n"
+" teq %[tmp], #0\n"
+" beq 2f\n"
+ WFE_SAFE("%[fixup]", "%[tmp]")
+"2:\n"
+" strexeq %[tmp], %[bit0], [%[lock]]\n"
+" teqeq %[tmp], #0\n"
" bne 1b"
- : "=&r" (tmp)
- : "r" (&lock->lock), "r" (1)
+ : [tmp] "=&r" (tmp), [fixup] "+r" (fixup)
+ : [lock] "r" (&lock->lock), [bit0] "r" (1)
: "cc");
smp_mb();
@@ -155,6 +176,7 @@
static inline void arch_spin_lock(arch_spinlock_t *lock)
{
unsigned long tmp, ticket, next_ticket;
+ unsigned long fixup = msm_krait_need_wfe_fixup;
/* Grab the next ticket and wait for it to be "served" */
__asm__ __volatile__(
@@ -166,12 +188,15 @@
" uxth %[ticket], %[ticket]\n"
"2:\n"
#ifdef CONFIG_CPU_32v6K
-" wfene\n"
+" beq 3f\n"
+ WFE_SAFE("%[fixup]", "%[tmp]")
+"3:\n"
#endif
" ldr %[tmp], [%[lockaddr]]\n"
" cmp %[ticket], %[tmp], lsr #16\n"
" bne 2b"
- : [ticket]"=&r" (ticket), [tmp]"=&r" (tmp), [next_ticket]"=&r" (next_ticket)
+ : [ticket]"=&r" (ticket), [tmp]"=&r" (tmp),
+ [next_ticket]"=&r" (next_ticket), [fixup]"+r" (fixup)
: [lockaddr]"r" (&lock->lock), [val1]"r" (1)
: "cc");
smp_mb();
@@ -220,13 +245,16 @@
static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
{
- unsigned long ticket;
+ unsigned long ticket, tmp, fixup = msm_krait_need_wfe_fixup;
/* Wait for now_serving == next_ticket */
__asm__ __volatile__(
#ifdef CONFIG_CPU_32v6K
" cmpne %[lockaddr], %[lockaddr]\n"
-"1: wfene\n"
+"1:\n"
+" beq 2f\n"
+ WFE_SAFE("%[fixup]", "%[tmp]")
+"2:\n"
#else
"1:\n"
#endif
@@ -235,7 +263,8 @@
" uxth %[ticket], %[ticket]\n"
" cmp %[ticket], #0\n"
" bne 1b"
- : [ticket]"=&r" (ticket)
+ : [ticket]"=&r" (ticket), [tmp]"=&r" (tmp),
+ [fixup]"+r" (fixup)
: [lockaddr]"r" (&lock->lock)
: "cc");
}
@@ -263,17 +292,19 @@
static inline void arch_write_lock(arch_rwlock_t *rw)
{
- unsigned long tmp;
+ unsigned long tmp, fixup = msm_krait_need_wfe_fixup;
__asm__ __volatile__(
-"1: ldrex %0, [%1]\n"
-" teq %0, #0\n"
- WFE("ne")
-" strexeq %0, %2, [%1]\n"
-" teq %0, #0\n"
+"1: ldrex %[tmp], [%[lock]]\n"
+" teq %[tmp], #0\n"
+" beq 2f\n"
+ WFE_SAFE("%[fixup]", "%[tmp]")
+"2:\n"
+" strexeq %[tmp], %[bit31], [%[lock]]\n"
+" teq %[tmp], #0\n"
" bne 1b"
- : "=&r" (tmp)
- : "r" (&rw->lock), "r" (0x80000000)
+ : [tmp] "=&r" (tmp), [fixup] "+r" (fixup)
+ : [lock] "r" (&rw->lock), [bit31] "r" (0x80000000)
: "cc");
smp_mb();
@@ -329,17 +360,19 @@
*/
static inline void arch_read_lock(arch_rwlock_t *rw)
{
- unsigned long tmp, tmp2;
+ unsigned long tmp, tmp2, fixup = msm_krait_need_wfe_fixup;
__asm__ __volatile__(
-"1: ldrex %0, [%2]\n"
-" adds %0, %0, #1\n"
-" strexpl %1, %0, [%2]\n"
- WFE("mi")
-" rsbpls %0, %1, #0\n"
+"1: ldrex %[tmp], [%[lock]]\n"
+" adds %[tmp], %[tmp], #1\n"
+" strexpl %[tmp2], %[tmp], [%[lock]]\n"
+" bpl 2f\n"
+ WFE_SAFE("%[fixup]", "%[tmp]")
+"2:\n"
+" rsbpls %[tmp], %[tmp2], #0\n"
" bmi 1b"
- : "=&r" (tmp), "=&r" (tmp2)
- : "r" (&rw->lock)
+ : [tmp] "=&r" (tmp), [tmp2] "=&r" (tmp2), [fixup] "+r" (fixup)
+ : [lock] "r" (&rw->lock)
: "cc");
smp_mb();
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index a8f2858..7d767c3 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -185,6 +185,7 @@
INIT_SETUP(16)
INIT_CALLS
CON_INITCALL
+ COMPAT_EXPORTS
SECURITY_INITCALL
INIT_RAM_FS
}
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index c23bc10..5e7965e 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -172,6 +172,7 @@
select HOLES_IN_ZONE if SPARSEMEM
select MSM_RUN_QUEUE_STATS
select ARM_HAS_SG_CHAIN
+ select MSM_KRAIT_WFE_FIXUP
config ARCH_MSM8930
bool "MSM8930"
@@ -203,6 +204,7 @@
select MSM_PM8X60 if PM
select HOLES_IN_ZONE if SPARSEMEM
select ARM_HAS_SG_CHAIN
+ select MSM_KRAIT_WFE_FIXUP
config ARCH_APQ8064
bool "APQ8064"
@@ -229,6 +231,7 @@
select MIGHT_HAVE_PCI
select ARCH_SUPPORTS_MSI
select ARM_HAS_SG_CHAIN
+ select MSM_KRAIT_WFE_FIXUP
config ARCH_MSM8974
bool "MSM8974"
@@ -370,6 +373,9 @@
select MSM_SMP
bool
+config MSM_KRAIT_WFE_FIXUP
+ bool
+
config ARCH_MSM_CORTEX_A5
bool
select HAVE_HW_BRKPT_RESERVED_RW_ACCESS
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 5cd93dc..4c020e3 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -23,6 +23,7 @@
endif
obj-y += acpuclock.o
+obj-$(CONFIG_ARCH_MSM_KRAIT) += acpuclock-krait.o
obj-$(CONFIG_ARCH_MSM7X27) += acpuclock-7627.o clock-pll.o
obj-$(CONFIG_ARCH_MSM_SCORPION) += pmu.o
obj-$(CONFIG_ARCH_MSM_SCORPIONMP) += perf_event_msm_l2.o
@@ -269,6 +270,7 @@
obj-$(CONFIG_ARCH_MSM8960) += saw-regulator.o
obj-$(CONFIG_ARCH_MSM8960) += devices-8960.o
obj-$(CONFIG_ARCH_APQ8064) += devices-8960.o devices-8064.o
+obj-$(CONFIG_ARCH_APQ8064) += acpuclock-8064.o
board-8960-all-objs += board-8960.o board-8960-camera.o board-8960-display.o board-8960-pmic.o board-8960-storage.o board-8960-gpiomux.o
board-8930-all-objs += board-8930.o board-8930-camera.o board-8930-display.o board-8930-pmic.o board-8930-storage.o board-8930-gpiomux.o devices-8930.o board-8930-gpu.o
board-8064-all-objs += board-8064.o board-8064-pmic.o board-8064-storage.o board-8064-gpiomux.o board-8064-camera.o board-8064-display.o board-8064-gpu.o
@@ -291,11 +293,11 @@
obj-$(CONFIG_ARCH_MSM9615) += board-9615.o devices-9615.o board-9615-regulator.o board-9615-gpiomux.o board-9615-storage.o board-9615-display.o
obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o clock-rpm.o clock-pll.o
obj-$(CONFIG_ARCH_MSM8974) += board-8974.o board-dt.o board-8974-regulator.o board-8974-gpiomux.o
-obj-$(CONFIG_ARCH_MSM8974) += acpuclock-krait.o acpuclock-8974.o
+obj-$(CONFIG_ARCH_MSM8974) += acpuclock-8974.o
obj-$(CONFIG_ARCH_MSM8974) += clock-local2.o clock-pll.o clock-8974.o clock-rpm.o clock-voter.o
obj-$(CONFIG_ARCH_MSM8974) += gdsc.o
obj-$(CONFIG_ARCH_MSM9625) += board-9625.o board-9625-gpiomux.o
-obj-$(CONFIG_ARCH_MSM8930) += acpuclock-krait.o acpuclock-8930.o acpuclock-8627.o
+obj-$(CONFIG_ARCH_MSM8930) += acpuclock-8930.o acpuclock-8627.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
@@ -337,7 +339,7 @@
obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-vcm.o
endif
obj-$(CONFIG_MSM_OCMEM) += ocmem.o ocmem_allocator.o ocmem_notifier.o
-obj-$(CONFIG_MSM_OCMEM) += ocmem_sched.o ocmem_api.o
+obj-$(CONFIG_MSM_OCMEM) += ocmem_sched.o ocmem_api.o ocmem_rdm.o
obj-$(CONFIG_ARCH_MSM7X27) += gpiomux-7x27.o gpiomux-v1.o gpiomux.o
obj-$(CONFIG_ARCH_MSM7X30) += gpiomux-7x30.o gpiomux-v1.o gpiomux.o
diff --git a/arch/arm/mach-msm/acpuclock-8064.c b/arch/arm/mach-msm/acpuclock-8064.c
new file mode 100644
index 0000000..d46d268
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-8064.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <mach/rpm-regulator.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
+
+#include "acpuclock.h"
+#include "acpuclock-krait.h"
+
+static struct hfpll_data hfpll_data __initdata = {
+ .mode_offset = 0x00,
+ .l_offset = 0x08,
+ .m_offset = 0x0C,
+ .n_offset = 0x10,
+ .config_offset = 0x04,
+ .config_val = 0x7845C665,
+ .has_droop_ctl = true,
+ .droop_offset = 0x14,
+ .droop_val = 0x0108C000,
+ .low_vdd_l_max = 40,
+ .vdd[HFPLL_VDD_NONE] = 0,
+ .vdd[HFPLL_VDD_LOW] = 945000,
+ .vdd[HFPLL_VDD_NOM] = 1050000,
+};
+
+static struct scalable scalable[] __initdata = {
+ [CPU0] = {
+ .hfpll_phys_base = 0x00903200,
+ .aux_clk_sel_phys = 0x02088014,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x4501,
+ .vreg[VREG_CORE] = { "krait0", 1300000, 1740000 },
+ .vreg[VREG_MEM] = { "krait0_mem", 1150000 },
+ .vreg[VREG_DIG] = { "krait0_dig", 1150000 },
+ .vreg[VREG_HFPLL_A] = { "krait0_hfpll", 1800000 },
+ },
+ [CPU1] = {
+ .hfpll_phys_base = 0x00903240,
+ .aux_clk_sel_phys = 0x02098014,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x5501,
+ .vreg[VREG_CORE] = { "krait1", 1300000, 1740000 },
+ .vreg[VREG_MEM] = { "krait1_mem", 1150000 },
+ .vreg[VREG_DIG] = { "krait1_dig", 1150000 },
+ .vreg[VREG_HFPLL_A] = { "krait1_hfpll", 1800000 },
+ },
+ [CPU2] = {
+ .hfpll_phys_base = 0x00903280,
+ .aux_clk_sel_phys = 0x020A8014,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x6501,
+ .vreg[VREG_CORE] = { "krait2", 1300000, 1740000 },
+ .vreg[VREG_MEM] = { "krait2_mem", 1150000 },
+ .vreg[VREG_DIG] = { "krait2_dig", 1150000 },
+ .vreg[VREG_HFPLL_A] = { "krait2_hfpll", 1800000 },
+ },
+ [CPU3] = {
+ .hfpll_phys_base = 0x009032C0,
+ .aux_clk_sel_phys = 0x020B8014,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x7501,
+ .vreg[VREG_CORE] = { "krait3", 1300000, 1740000 },
+ .vreg[VREG_MEM] = { "krait3_mem", 1150000 },
+ .vreg[VREG_DIG] = { "krait3_dig", 1150000 },
+ .vreg[VREG_HFPLL_A] = { "krait3_hfpll", 1800000 },
+ },
+ [L2] = {
+ .hfpll_phys_base = 0x00903300,
+ .aux_clk_sel_phys = 0x02011028,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x0500,
+ .vreg[VREG_HFPLL_A] = { "l2_hfpll", 1800000 },
+ },
+};
+
+static struct msm_bus_paths bw_level_tbl[] __initdata = {
+ [0] = BW_MBPS(640), /* At least 80 MHz on bus. */
+ [1] = BW_MBPS(1064), /* At least 133 MHz on bus. */
+ [2] = BW_MBPS(1600), /* At least 200 MHz on bus. */
+ [3] = BW_MBPS(2128), /* At least 266 MHz on bus. */
+ [4] = BW_MBPS(3200), /* At least 400 MHz on bus. */
+ [5] = BW_MBPS(4264), /* At least 533 MHz on bus. */
+};
+
+static struct msm_bus_scale_pdata bus_scale_data __initdata = {
+ .usecase = bw_level_tbl,
+ .num_usecases = ARRAY_SIZE(bw_level_tbl),
+ .active_only = 1,
+ .name = "acpuclk-8064",
+};
+
+static struct l2_level l2_freq_tbl[] __initdata __initdata = {
+ [0] = { {STBY_KHZ, QSB, 0, 0, 0x00 }, 1050000, 1050000, 0 },
+ [1] = { { 384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
+ [2] = { { 432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 2 },
+ [3] = { { 486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 2 },
+ [4] = { { 540000, HFPLL, 2, 0, 0x28 }, 1050000, 1050000, 2 },
+ [5] = { { 594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
+ [6] = { { 648000, HFPLL, 1, 0, 0x18 }, 1050000, 1050000, 4 },
+ [7] = { { 702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 4 },
+ [8] = { { 756000, HFPLL, 1, 0, 0x1C }, 1150000, 1150000, 4 },
+ [9] = { { 810000, HFPLL, 1, 0, 0x1E }, 1150000, 1150000, 4 },
+ [10] = { { 864000, HFPLL, 1, 0, 0x20 }, 1150000, 1150000, 4 },
+ [11] = { { 918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 5 },
+ [12] = { { 972000, HFPLL, 1, 0, 0x24 }, 1150000, 1150000, 5 },
+ [13] = { { 1026000, HFPLL, 1, 0, 0x26 }, 1150000, 1150000, 5 },
+ [14] = { { 1080000, HFPLL, 1, 0, 0x28 }, 1150000, 1150000, 5 },
+ [15] = { { 1134000, HFPLL, 1, 0, 0x2A }, 1150000, 1150000, 5 },
+};
+
+static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
+ { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 950000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 950000 },
+ { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 975000 },
+ { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(7), 975000 },
+ { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(7), 1000000 },
+ { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(7), 1000000 },
+ { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(7), 1025000 },
+ { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(7), 1025000 },
+ { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(7), 1075000 },
+ { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(7), 1075000 },
+ { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(7), 1100000 },
+ { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(7), 1100000 },
+ { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(7), 1125000 },
+ { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(7), 1125000 },
+ { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1175000 },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1175000 },
+ { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1200000 },
+ { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1200000 },
+ { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1225000 },
+ { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1225000 },
+ { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1237500 },
+ { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1237500 },
+ { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1250000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
+ { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 900000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 900000 },
+ { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 925000 },
+ { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(7), 925000 },
+ { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(7), 950000 },
+ { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(7), 950000 },
+ { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(7), 975000 },
+ { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(7), 975000 },
+ { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(7), 1025000 },
+ { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(7), 1025000 },
+ { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(7), 1050000 },
+ { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(7), 1050000 },
+ { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(7), 1075000 },
+ { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(7), 1075000 },
+ { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1125000 },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1125000 },
+ { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1150000 },
+ { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1150000 },
+ { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1175000 },
+ { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1175000 },
+ { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1187500 },
+ { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1187500 },
+ { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1200000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
+ { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 850000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 850000 },
+ { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 875000 },
+ { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(7), 875000 },
+ { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(7), 900000 },
+ { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(7), 900000 },
+ { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(7), 925000 },
+ { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(7), 925000 },
+ { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(7), 975000 },
+ { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(7), 975000 },
+ { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(7), 1000000 },
+ { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(7), 1000000 },
+ { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(7), 1025000 },
+ { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(7), 1025000 },
+ { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1075000 },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1075000 },
+ { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1100000 },
+ { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1100000 },
+ { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1125000 },
+ { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1125000 },
+ { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1137500 },
+ { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1137500 },
+ { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1150000 },
+ { 0, { 0 } }
+};
+
+static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
+ [PVS_SLOW] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow) },
+ [PVS_NOMINAL] = { acpu_freq_tbl_nom, sizeof(acpu_freq_tbl_nom) },
+ [PVS_FAST] = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast) },
+ /* TODO: update the faster table when data is available */
+ [PVS_FASTER] = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast) },
+};
+
+static struct acpuclk_krait_params acpuclk_8064_params __initdata = {
+ .scalable = scalable,
+ .scalable_size = sizeof(scalable),
+ .hfpll_data = &hfpll_data,
+ .pvs_tables = pvs_tables,
+ .l2_freq_tbl = l2_freq_tbl,
+ .l2_freq_tbl_size = sizeof(l2_freq_tbl),
+ .bus_scale = &bus_scale_data,
+ .qfprom_phys_base = 0x00700000,
+};
+
+static int __init acpuclk_8064_probe(struct platform_device *pdev)
+{
+ return acpuclk_krait_init(&pdev->dev, &acpuclk_8064_params);
+}
+
+static struct platform_driver acpuclk_8064_driver = {
+ .driver = {
+ .name = "acpuclk-8064",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init acpuclk_8064_init(void)
+{
+ return platform_driver_probe(&acpuclk_8064_driver,
+ acpuclk_8064_probe);
+}
+device_initcall(acpuclk_8064_init);
diff --git a/arch/arm/mach-msm/acpuclock-8627.c b/arch/arm/mach-msm/acpuclock-8627.c
index 45f2096..8060803 100644
--- a/arch/arm/mach-msm/acpuclock-8627.c
+++ b/arch/arm/mach-msm/acpuclock-8627.c
@@ -27,7 +27,7 @@
#define LVL_NOM RPM_VREG_CORNER_NOMINAL
#define LVL_HIGH RPM_VREG_CORNER_HIGH
-static struct hfpll_data hfpll_data = {
+static struct hfpll_data hfpll_data __initdata = {
.mode_offset = 0x00,
.l_offset = 0x08,
.m_offset = 0x0C,
@@ -43,10 +43,9 @@
.vdd[HFPLL_VDD_NOM] = LVL_NOM,
};
-static struct scalable scalable[] = {
+static struct scalable scalable[] __initdata = {
[CPU0] = {
.hfpll_phys_base = 0x00903200,
- .hfpll_data = &hfpll_data,
.aux_clk_sel_phys = 0x02088014,
.aux_clk_sel = 3,
.l2cpmr_iaddr = 0x4501,
@@ -57,7 +56,6 @@
},
[CPU1] = {
.hfpll_phys_base = 0x00903300,
- .hfpll_data = &hfpll_data,
.aux_clk_sel_phys = 0x02098014,
.aux_clk_sel = 3,
.l2cpmr_iaddr = 0x5501,
@@ -68,7 +66,6 @@
},
[L2] = {
.hfpll_phys_base = 0x00903400,
- .hfpll_data = &hfpll_data,
.aux_clk_sel_phys = 0x02011028,
.aux_clk_sel = 3,
.l2cpmr_iaddr = 0x0500,
@@ -76,7 +73,7 @@
},
};
-static struct msm_bus_paths bw_level_tbl[] = {
+static struct msm_bus_paths bw_level_tbl[] __initdata = {
[0] = BW_MBPS(640), /* At least 80 MHz on bus. */
[1] = BW_MBPS(1064), /* At least 133 MHz on bus. */
[2] = BW_MBPS(1600), /* At least 200 MHz on bus. */
@@ -84,7 +81,7 @@
[4] = BW_MBPS(3200), /* At least 400 MHz on bus. */
};
-static struct msm_bus_scale_pdata bus_scale_data = {
+static struct msm_bus_scale_pdata bus_scale_data __initdata = {
.usecase = bw_level_tbl,
.num_usecases = ARRAY_SIZE(bw_level_tbl),
.active_only = 1,
@@ -92,8 +89,7 @@
};
/* TODO: Update vdd_dig, vdd_mem and bw when data is available. */
-#define L2(x) (&l2_freq_tbl[(x)])
-static struct l2_level l2_freq_tbl[] = {
+static struct l2_level l2_freq_tbl[] __initdata = {
[0] = { {STBY_KHZ, QSB, 0, 0, 0x00 }, LVL_NOM, 1050000, 0 },
[1] = { { 384000, PLL_8, 0, 2, 0x00 }, LVL_NOM, 1050000, 1 },
[2] = { { 432000, HFPLL, 2, 0, 0x20 }, LVL_NOM, 1050000, 1 },
@@ -110,7 +106,7 @@
};
/* TODO: Update core voltages when data is available. */
-static struct acpu_level acpu_freq_tbl[] = {
+static struct acpu_level acpu_freq_tbl[] __initdata = {
{ 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 900000 },
{ 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 900000 },
{ 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(5), 925000 },
@@ -127,14 +123,20 @@
{ 0, { 0 } }
};
-static struct acpuclk_krait_params acpuclk_8627_params = {
+static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
+ [PVS_SLOW] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
+ [PVS_NOMINAL] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
+ [PVS_FAST] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
+};
+
+static struct acpuclk_krait_params acpuclk_8627_params __initdata = {
.scalable = scalable,
- .pvs_acpu_freq_tbl[PVS_SLOW] = acpu_freq_tbl,
- .pvs_acpu_freq_tbl[PVS_NOMINAL] = acpu_freq_tbl,
- .pvs_acpu_freq_tbl[PVS_FAST] = acpu_freq_tbl,
+ .scalable_size = sizeof(scalable),
+ .hfpll_data = &hfpll_data,
+ .pvs_tables = pvs_tables,
.l2_freq_tbl = l2_freq_tbl,
- .l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl),
- .bus_scale_data = &bus_scale_data,
+ .l2_freq_tbl_size = sizeof(l2_freq_tbl),
+ .bus_scale = &bus_scale_data,
.qfprom_phys_base = 0x00700000,
};
diff --git a/arch/arm/mach-msm/acpuclock-8930.c b/arch/arm/mach-msm/acpuclock-8930.c
index d60b4eb..d04ce03 100644
--- a/arch/arm/mach-msm/acpuclock-8930.c
+++ b/arch/arm/mach-msm/acpuclock-8930.c
@@ -27,7 +27,7 @@
#define LVL_NOM RPM_VREG_CORNER_NOMINAL
#define LVL_HIGH RPM_VREG_CORNER_HIGH
-static struct hfpll_data hfpll_data = {
+static struct hfpll_data hfpll_data __initdata = {
.mode_offset = 0x00,
.l_offset = 0x08,
.m_offset = 0x0C,
@@ -43,10 +43,9 @@
.vdd[HFPLL_VDD_NOM] = LVL_NOM,
};
-static struct scalable scalable[] = {
+static struct scalable scalable[] __initdata = {
[CPU0] = {
.hfpll_phys_base = 0x00903200,
- .hfpll_data = &hfpll_data,
.aux_clk_sel_phys = 0x02088014,
.aux_clk_sel = 3,
.l2cpmr_iaddr = 0x4501,
@@ -57,7 +56,6 @@
},
[CPU1] = {
.hfpll_phys_base = 0x00903300,
- .hfpll_data = &hfpll_data,
.aux_clk_sel_phys = 0x02098014,
.aux_clk_sel = 3,
.l2cpmr_iaddr = 0x5501,
@@ -68,7 +66,6 @@
},
[L2] = {
.hfpll_phys_base = 0x00903400,
- .hfpll_data = &hfpll_data,
.aux_clk_sel_phys = 0x02011028,
.aux_clk_sel = 3,
.l2cpmr_iaddr = 0x0500,
@@ -76,7 +73,7 @@
},
};
-static struct msm_bus_paths bw_level_tbl[] = {
+static struct msm_bus_paths bw_level_tbl[] __initdata = {
[0] = BW_MBPS(640), /* At least 80 MHz on bus. */
[1] = BW_MBPS(1064), /* At least 133 MHz on bus. */
[2] = BW_MBPS(1600), /* At least 200 MHz on bus. */
@@ -87,7 +84,7 @@
[7] = BW_MBPS(4264), /* At least 533 MHz on bus. */
};
-static struct msm_bus_scale_pdata bus_scale_data = {
+static struct msm_bus_scale_pdata bus_scale_data __initdata = {
.usecase = bw_level_tbl,
.num_usecases = ARRAY_SIZE(bw_level_tbl),
.active_only = 1,
@@ -95,8 +92,7 @@
};
/* TODO: Update vdd_dig, vdd_mem and bw when data is available. */
-#define L2(x) (&l2_freq_tbl[(x)])
-static struct l2_level l2_freq_tbl[] = {
+static struct l2_level l2_freq_tbl[] __initdata = {
[0] = { {STBY_KHZ, QSB, 0, 0, 0x00 }, LVL_NOM, 1050000, 0 },
[1] = { { 384000, PLL_8, 0, 2, 0x00 }, LVL_NOM, 1050000, 1 },
[2] = { { 432000, HFPLL, 2, 0, 0x20 }, LVL_NOM, 1050000, 2 },
@@ -116,7 +112,7 @@
[16] = { { 1188000, HFPLL, 1, 0, 0x2C }, LVL_HIGH, 1150000, 7 },
};
-static struct acpu_level acpu_freq_tbl_slow[] = {
+static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
{ 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 950000 },
{ 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 950000 },
{ 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 975000 },
@@ -137,7 +133,7 @@
{ 0, { 0 } }
};
-static struct acpu_level acpu_freq_tbl_nom[] = {
+static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
{ 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 925000 },
{ 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 925000 },
{ 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 950000 },
@@ -158,7 +154,7 @@
{ 0, { 0 } }
};
-static struct acpu_level acpu_freq_tbl_fast[] = {
+static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
{ 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 900000 },
{ 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 900000 },
{ 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 900000 },
@@ -179,14 +175,20 @@
{ 0, { 0 } }
};
-static struct acpuclk_krait_params acpuclk_8930_params = {
+static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
+ [PVS_SLOW] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow) },
+ [PVS_NOMINAL] = { acpu_freq_tbl_nom, sizeof(acpu_freq_tbl_nom) },
+ [PVS_FAST] = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast) },
+};
+
+static struct acpuclk_krait_params acpuclk_8930_params __initdata = {
.scalable = scalable,
- .pvs_acpu_freq_tbl[PVS_SLOW] = acpu_freq_tbl_slow,
- .pvs_acpu_freq_tbl[PVS_NOMINAL] = acpu_freq_tbl_nom,
- .pvs_acpu_freq_tbl[PVS_FAST] = acpu_freq_tbl_fast,
+ .scalable_size = sizeof(scalable),
+ .hfpll_data = &hfpll_data,
+ .pvs_tables = pvs_tables,
.l2_freq_tbl = l2_freq_tbl,
- .l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl),
- .bus_scale_data = &bus_scale_data,
+ .l2_freq_tbl_size = sizeof(l2_freq_tbl),
+ .bus_scale = &bus_scale_data,
.qfprom_phys_base = 0x00700000,
};
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index 8947c9f..8623c2b 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -1,4 +1,5 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/*
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -10,318 +11,66 @@
* GNU General Public License for more details.
*/
-#define pr_fmt(fmt) "%s: " fmt, __func__
-
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <linux/cpufreq.h>
-#include <linux/cpu.h>
-#include <linux/regulator/consumer.h>
#include <linux/platform_device.h>
-
-#include <asm/mach-types.h>
-#include <asm/cpu.h>
-
-#include <mach/board.h>
-#include <mach/msm_iomap.h>
#include <mach/rpm-regulator.h>
-#include <mach/msm_bus.h>
#include <mach/msm_bus_board.h>
-#include <mach/socinfo.h>
-#include <mach/msm-krait-l2-accessors.h>
-#include <mach/rpm-regulator.h>
+#include <mach/msm_bus.h>
#include "acpuclock.h"
-#include "pm.h"
+#include "acpuclock-krait.h"
-/*
- * Source IDs.
- * These must be negative to not overlap with the source IDs
- * used by the 8x60 local clock driver.
- */
-#define PLL_8 0
-#define HFPLL -1
-#define QSB -2
-
-/* Mux source selects. */
-#define PRI_SRC_SEL_SEC_SRC 0
-#define PRI_SRC_SEL_HFPLL 1
-#define PRI_SRC_SEL_HFPLL_DIV2 2
-#define SEC_SRC_SEL_QSB 0
-#define SEC_SRC_SEL_AUX 2
-
-/* HFPLL registers offsets. */
-#define HFPLL_MODE 0x00
-#define HFPLL_CONFIG_CTL 0x04
-#define HFPLL_L_VAL 0x08
-#define HFPLL_M_VAL 0x0C
-#define HFPLL_N_VAL 0x10
-#define HFPLL_DROOP_CTL 0x14
-
-/* CP15 L2 indirect addresses. */
-#define L2CPMR_IADDR 0x500
-#define L2CPUCPMR_IADDR 0x501
-
-#define STBY_KHZ 1
-
-#define HFPLL_LOW_VDD_PLL_L_MAX 0x28
-
-#define SECCLKAGD BIT(4)
-
-/* PTE EFUSE register. */
-#define QFPROM_PTE_EFUSE_ADDR (MSM_QFPROM_BASE + 0x00C0)
-
-/* Corner type vreg VDD values */
-#define LVL_NONE RPM_VREG_CORNER_NONE
-#define LVL_LOW RPM_VREG_CORNER_LOW
-#define LVL_NOM RPM_VREG_CORNER_NOMINAL
-#define LVL_HIGH RPM_VREG_CORNER_HIGH
-
-enum scalables {
- CPU0 = 0,
- CPU1,
- CPU2,
- CPU3,
- L2,
- NUM_SCALABLES
+static struct hfpll_data hfpll_data __initdata = {
+ .mode_offset = 0x00,
+ .l_offset = 0x08,
+ .m_offset = 0x0C,
+ .n_offset = 0x10,
+ .config_offset = 0x04,
+ .config_val = 0x7845C665,
+ .has_droop_ctl = true,
+ .droop_offset = 0x14,
+ .droop_val = 0x0108C000,
+ .low_vdd_l_max = 40,
+ .vdd[HFPLL_VDD_NONE] = 0,
+ .vdd[HFPLL_VDD_LOW] = 850000,
+ .vdd[HFPLL_VDD_NOM] = 1050000,
};
-enum vregs {
- VREG_CORE,
- VREG_MEM,
- VREG_DIG,
- VREG_HFPLL_A,
- VREG_HFPLL_B,
- NUM_VREG
-};
-
-enum hfpll_vdd_levels {
- HFPLL_VDD_NONE,
- HFPLL_VDD_LOW,
- HFPLL_VDD_NOM
-};
-
-enum pvs {
- PVS_SLOW,
- PVS_NOM,
- PVS_FAST,
- PVS_FASTER,
- NUM_PVS
-};
-
-struct vreg {
- const char name[15];
- const unsigned int max_vdd;
- const int rpm_vreg_voter;
- const int rpm_vreg_id;
- struct regulator *reg;
- unsigned int cur_vdd;
-};
-
-struct core_speed {
- unsigned int khz;
- int src;
- unsigned int pri_src_sel;
- unsigned int sec_src_sel;
- unsigned int pll_l_val;
-};
-
-struct l2_level {
- struct core_speed speed;
- unsigned int vdd_dig;
- unsigned int vdd_mem;
- unsigned int bw_level;
-};
-
-struct acpu_level {
- unsigned int use_for_scaling;
- struct core_speed speed;
- struct l2_level *l2_level;
- unsigned int vdd_core;
-};
-
-struct scalable {
- void * __iomem const hfpll_base;
- void * __iomem const aux_clk_sel;
- const uint32_t l2cpmr_iaddr;
- struct core_speed *current_speed;
- struct l2_level *l2_vote;
- struct vreg vreg[NUM_VREG];
- unsigned int *hfpll_vdd_tbl;
- bool regulators_initialized;
- bool clocks_initialized;
-};
-
-static unsigned int hfpll_vdd_tbl_8960[] = {
- [HFPLL_VDD_NONE] = 0,
- [HFPLL_VDD_LOW] = 850000,
- [HFPLL_VDD_NOM] = 1050000
-};
-
-static unsigned int hfpll_vdd_tbl_8064[] = {
- [HFPLL_VDD_NONE] = 0,
- [HFPLL_VDD_LOW] = 945000,
- [HFPLL_VDD_NOM] = 1050000
-};
-
-static struct scalable scalable_8960[] = {
+static struct scalable scalable[] __initdata = {
[CPU0] = {
- .hfpll_base = MSM_HFPLL_BASE + 0x200,
- .aux_clk_sel = MSM_ACC0_BASE + 0x014,
- .l2cpmr_iaddr = L2CPUCPMR_IADDR,
- .vreg[VREG_CORE] = { "krait0", 1300000 },
- .vreg[VREG_MEM] = { "krait0_mem", 1150000,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8921_L24 },
- .vreg[VREG_DIG] = { "krait0_dig", 1150000,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8921_S3 },
- .vreg[VREG_HFPLL_A] = { "hfpll0_s8", 2100000,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8921_S8 },
- .vreg[VREG_HFPLL_B] = { "hfpll0_l23", 1800000,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8921_L23 },
- },
+ .hfpll_phys_base = 0x00903200,
+ .aux_clk_sel_phys = 0x02088014,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x4501,
+ .vreg[VREG_CORE] = { "krait0", 1300000, 3200000 },
+ .vreg[VREG_MEM] = { "krait0_mem", 1150000 },
+ .vreg[VREG_DIG] = { "krait0_dig", 1150000 },
+ .vreg[VREG_HFPLL_A] = { "krait0_s8", 2050000 },
+ .vreg[VREG_HFPLL_B] = { "krait0_l23", 1800000 },
+ },
[CPU1] = {
- .hfpll_base = MSM_HFPLL_BASE + 0x300,
- .aux_clk_sel = MSM_ACC1_BASE + 0x014,
- .l2cpmr_iaddr = L2CPUCPMR_IADDR,
- .vreg[VREG_CORE] = { "krait1", 1300000 },
- .vreg[VREG_MEM] = { "krait1_mem", 1150000,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8921_L24 },
- .vreg[VREG_DIG] = { "krait1_dig", 1150000,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8921_S3 },
- .vreg[VREG_HFPLL_A] = { "hfpll1_s8", 2100000,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8921_S8 },
- .vreg[VREG_HFPLL_B] = { "hfpll1_l23", 1800000,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8921_L23 },
- },
+ .hfpll_phys_base = 0x00903300,
+ .aux_clk_sel_phys = 0x02098014,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x5501,
+ .vreg[VREG_CORE] = { "krait1", 1300000, 3200000 },
+ .vreg[VREG_MEM] = { "krait1_mem", 1150000 },
+ .vreg[VREG_DIG] = { "krait1_dig", 1150000 },
+ .vreg[VREG_HFPLL_A] = { "krait1_s8", 2050000 },
+ .vreg[VREG_HFPLL_B] = { "krait1_l23", 1800000 },
+ },
[L2] = {
- .hfpll_base = MSM_HFPLL_BASE + 0x400,
- .hfpll_vdd_tbl = hfpll_vdd_tbl_8960,
- .aux_clk_sel = MSM_APCS_GCC_BASE + 0x028,
- .l2cpmr_iaddr = L2CPMR_IADDR,
- .vreg[VREG_HFPLL_A] = { "hfpll_l2_s8", 2100000,
- RPM_VREG_VOTER6,
- RPM_VREG_ID_PM8921_S8 },
- .vreg[VREG_HFPLL_B] = { "hfpll_l2_l23", 1800000,
- RPM_VREG_VOTER6,
- RPM_VREG_ID_PM8921_L23 },
- },
+ .hfpll_phys_base = 0x00903400,
+ .aux_clk_sel_phys = 0x02011028,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x0500,
+ .vreg[VREG_HFPLL_A] = { "l2_s8", 2050000 },
+ .vreg[VREG_HFPLL_B] = { "l2_l23", 1800000 },
+ },
};
-static DEFINE_MUTEX(driver_lock);
-static DEFINE_SPINLOCK(l2_lock);
-
-static struct scalable scalable_8064[] = {
- [CPU0] = {
- .hfpll_base = MSM_HFPLL_BASE + 0x200,
- .aux_clk_sel = MSM_ACC0_BASE + 0x014,
- .l2cpmr_iaddr = L2CPUCPMR_IADDR,
- .vreg[VREG_CORE] = { "krait0", 1300000 },
- .vreg[VREG_MEM] = { "krait0_mem", 1150000,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8921_L24 },
- .vreg[VREG_DIG] = { "krait0_dig", 1150000,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8921_S3 },
- .vreg[VREG_HFPLL_B] = { "hfpll0", 1800000,
- RPM_VREG_VOTER1,
- RPM_VREG_ID_PM8921_LVS7 },
- },
- [CPU1] = {
- .hfpll_base = MSM_HFPLL_BASE + 0x240,
- .aux_clk_sel = MSM_ACC1_BASE + 0x014,
- .l2cpmr_iaddr = L2CPUCPMR_IADDR,
- .vreg[VREG_CORE] = { "krait1", 1300000 },
- .vreg[VREG_MEM] = { "krait1_mem", 1150000,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8921_L24 },
- .vreg[VREG_DIG] = { "krait1_dig", 1150000,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8921_S3 },
- .vreg[VREG_HFPLL_B] = { "hfpll1", 1800000,
- RPM_VREG_VOTER2,
- RPM_VREG_ID_PM8921_LVS7 },
- },
- [CPU2] = {
- .hfpll_base = MSM_HFPLL_BASE + 0x280,
- .aux_clk_sel = MSM_ACC2_BASE + 0x014,
- .l2cpmr_iaddr = L2CPUCPMR_IADDR,
- .vreg[VREG_CORE] = { "krait2", 1300000 },
- .vreg[VREG_MEM] = { "krait2_mem", 1150000,
- RPM_VREG_VOTER4,
- RPM_VREG_ID_PM8921_L24 },
- .vreg[VREG_DIG] = { "krait2_dig", 1150000,
- RPM_VREG_VOTER4,
- RPM_VREG_ID_PM8921_S3 },
- .vreg[VREG_HFPLL_B] = { "hfpll2", 1800000,
- RPM_VREG_VOTER4,
- RPM_VREG_ID_PM8921_LVS7 },
- },
- [CPU3] = {
- .hfpll_base = MSM_HFPLL_BASE + 0x2C0,
- .aux_clk_sel = MSM_ACC3_BASE + 0x014,
- .l2cpmr_iaddr = L2CPUCPMR_IADDR,
- .vreg[VREG_CORE] = { "krait3", 1300000 },
- .vreg[VREG_MEM] = { "krait3_mem", 1150000,
- RPM_VREG_VOTER5,
- RPM_VREG_ID_PM8921_L24 },
- .vreg[VREG_DIG] = { "krait3_dig", 1150000,
- RPM_VREG_VOTER5,
- RPM_VREG_ID_PM8921_S3 },
- .vreg[VREG_HFPLL_B] = { "hfpll3", 1800000,
- RPM_VREG_VOTER5,
- RPM_VREG_ID_PM8921_LVS7 },
- },
- [L2] = {
- .hfpll_base = MSM_HFPLL_BASE + 0x300,
- .hfpll_vdd_tbl = hfpll_vdd_tbl_8064,
- .aux_clk_sel = MSM_APCS_GCC_BASE + 0x028,
- .l2cpmr_iaddr = L2CPMR_IADDR,
- .vreg[VREG_HFPLL_B] = { "hfpll_l2", 1800000,
- RPM_VREG_VOTER6,
- RPM_VREG_ID_PM8921_LVS7 },
- },
-};
-
-static struct l2_level *l2_freq_tbl;
-static struct acpu_level *acpu_freq_tbl;
-static int l2_freq_tbl_size;
-static struct scalable *scalable;
-#define SCALABLE_TO_CPU(sc) ((sc) - scalable)
-
-/* Instantaneous bandwidth requests in MB/s. */
-#define BW_MBPS(_bw) \
- { \
- .vectors = (struct msm_bus_vectors[]){ \
- {\
- .src = MSM_BUS_MASTER_AMPSS_M0, \
- .dst = MSM_BUS_SLAVE_EBI_CH0, \
- .ib = (_bw) * 1000000UL, \
- .ab = (_bw) * 100000UL, \
- }, \
- { \
- .src = MSM_BUS_MASTER_AMPSS_M1, \
- .dst = MSM_BUS_SLAVE_EBI_CH0, \
- .ib = (_bw) * 1000000UL, \
- .ab = (_bw) * 100000UL, \
- }, \
- }, \
- .num_paths = 2, \
- }
-static struct msm_bus_paths bw_level_tbl[] = {
+static struct msm_bus_paths bw_level_tbl[] __initdata = {
[0] = BW_MBPS(640), /* At least 80 MHz on bus. */
[1] = BW_MBPS(1064), /* At least 133 MHz on bus. */
[2] = BW_MBPS(1600), /* At least 200 MHz on bus. */
@@ -329,70 +78,16 @@
[4] = BW_MBPS(3200), /* At least 400 MHz on bus. */
[5] = BW_MBPS(3600), /* At least 450 MHz on bus. */
[6] = BW_MBPS(3936), /* At least 492 MHz on bus. */
- [7] = BW_MBPS(4264), /* At least 533 MHz on bus. */
};
-static struct msm_bus_scale_pdata bus_client_pdata = {
+static struct msm_bus_scale_pdata bus_scale_data __initdata = {
.usecase = bw_level_tbl,
.num_usecases = ARRAY_SIZE(bw_level_tbl),
.active_only = 1,
- .name = "acpuclock",
+ .name = "acpuclk-8960",
};
-static uint32_t bus_perf_client;
-
-/* TODO: Update vdd_dig and vdd_mem when voltage data is available. */
-#define L2(x) (&l2_freq_tbl_8960_kraitv1[(x)])
-static struct l2_level l2_freq_tbl_8960_kraitv1[] = {
- [0] = { {STBY_KHZ, QSB, 0, 0, 0x00 }, 1050000, 1050000, 0 },
- [1] = { { 384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
- [2] = { { 432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 1 },
- [3] = { { 486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 1 },
- [4] = { { 540000, HFPLL, 2, 0, 0x28 }, 1050000, 1050000, 1 },
- [5] = { { 594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
- [6] = { { 648000, HFPLL, 1, 0, 0x18 }, 1050000, 1050000, 2 },
- [7] = { { 702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 2 },
- [8] = { { 756000, HFPLL, 1, 0, 0x1C }, 1150000, 1150000, 2 },
- [9] = { { 810000, HFPLL, 1, 0, 0x1E }, 1150000, 1150000, 3 },
- [10] = { { 864000, HFPLL, 1, 0, 0x20 }, 1150000, 1150000, 3 },
- [11] = { { 918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 3 },
-};
-
-static struct acpu_level acpu_freq_tbl_8960_kraitv1_slow[] = {
- { 0, {STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 900000 },
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 900000 },
- { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 925000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 925000 },
- { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 937500 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(6), 962500 },
- { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 987500 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 1000000 },
- { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(11), 1025000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(11), 1062500 },
- { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(11), 1062500 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(11), 1087500 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_8960_kraitv1_nom_fast[] = {
- { 0, {STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 862500 },
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 862500 },
- { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 862500 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 887500 },
- { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 900000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(6), 925000 },
- { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 925000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 937500 },
- { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(11), 962500 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(11), 1012500 },
- { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(11), 1025000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(11), 1025000 },
- { 0, { 0 } }
-};
-
-#undef L2
-#define L2(x) (&l2_freq_tbl_8960_kraitv2[(x)])
-static struct l2_level l2_freq_tbl_8960_kraitv2[] = {
+static struct l2_level l2_freq_tbl[] __initdata = {
[0] = { {STBY_KHZ, QSB, 0, 0, 0x00 }, 1050000, 1050000, 0 },
[1] = { { 384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
[2] = { { 432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 2 },
@@ -415,7 +110,7 @@
[19] = { { 1350000, HFPLL, 1, 0, 0x32 }, 1150000, 1150000, 6 },
};
-static struct acpu_level acpu_freq_tbl_8960_kraitv2_slow[] = {
+static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
{ 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 950000 },
{ 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 950000 },
{ 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 975000 },
@@ -442,7 +137,7 @@
{ 0, { 0 } }
};
-static struct acpu_level acpu_freq_tbl_8960_kraitv2_nom[] = {
+static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
{ 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 900000 },
{ 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 900000 },
{ 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 925000 },
@@ -469,7 +164,7 @@
{ 0, { 0 } }
};
-static struct acpu_level acpu_freq_tbl_8960_kraitv2_fast[] = {
+static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
{ 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 850000 },
{ 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 850000 },
{ 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 875000 },
@@ -496,935 +191,26 @@
{ 0, { 0 } }
};
-/* TODO: Update vdd_dig and vdd_mem when voltage data is available. */
-#undef L2
-#define L2(x) (&l2_freq_tbl_8064[(x)])
-static struct l2_level l2_freq_tbl_8064[] = {
- [0] = { {STBY_KHZ, QSB, 0, 0, 0x00 }, 1050000, 1050000, 0 },
- [1] = { { 384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
- [2] = { { 432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 2 },
- [3] = { { 486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 2 },
- [4] = { { 540000, HFPLL, 2, 0, 0x28 }, 1050000, 1050000, 2 },
- [5] = { { 594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
- [6] = { { 648000, HFPLL, 1, 0, 0x18 }, 1050000, 1050000, 4 },
- [7] = { { 702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 4 },
- [8] = { { 756000, HFPLL, 1, 0, 0x1C }, 1150000, 1150000, 4 },
- [9] = { { 810000, HFPLL, 1, 0, 0x1E }, 1150000, 1150000, 4 },
- [10] = { { 864000, HFPLL, 1, 0, 0x20 }, 1150000, 1150000, 4 },
- [11] = { { 918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 7 },
- [12] = { { 972000, HFPLL, 1, 0, 0x24 }, 1150000, 1150000, 7 },
- [13] = { { 1026000, HFPLL, 1, 0, 0x26 }, 1150000, 1150000, 7 },
- [14] = { { 1080000, HFPLL, 1, 0, 0x28 }, 1150000, 1150000, 7 },
- [15] = { { 1134000, HFPLL, 1, 0, 0x2A }, 1150000, 1150000, 7 },
+static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
+ [PVS_SLOW] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow) },
+ [PVS_NOMINAL] = { acpu_freq_tbl_nom, sizeof(acpu_freq_tbl_nom) },
+ [PVS_FAST] = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast) },
};
-/* TODO: Update core voltages when data is available. */
-static struct acpu_level acpu_freq_tbl_8064_slow[] = {
- { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 950000 },
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 950000 },
- { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 975000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(7), 975000 },
- { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(7), 1000000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(7), 1000000 },
- { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(7), 1025000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(7), 1025000 },
- { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(7), 1075000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(7), 1075000 },
- { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(7), 1100000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(7), 1100000 },
- { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(7), 1125000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(7), 1125000 },
- { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1175000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1175000 },
- { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1200000 },
- { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1200000 },
- { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1225000 },
- { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1225000 },
- { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1237500 },
- { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1237500 },
- { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1250000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_8064_nom[] = {
- { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 900000 },
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 900000 },
- { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 925000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(7), 925000 },
- { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(7), 950000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(7), 950000 },
- { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(7), 975000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(7), 975000 },
- { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(7), 1025000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(7), 1025000 },
- { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(7), 1050000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(7), 1050000 },
- { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(7), 1075000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(7), 1075000 },
- { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1125000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1125000 },
- { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1150000 },
- { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1150000 },
- { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1175000 },
- { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1175000 },
- { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1187500 },
- { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1187500 },
- { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1200000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_8064_fast[] = {
- { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 850000 },
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 850000 },
- { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 875000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(7), 875000 },
- { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(7), 900000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(7), 900000 },
- { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(7), 925000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(7), 925000 },
- { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(7), 975000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(7), 975000 },
- { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(7), 1000000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(7), 1000000 },
- { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(7), 1025000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(7), 1025000 },
- { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1075000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1075000 },
- { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1100000 },
- { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1100000 },
- { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1125000 },
- { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1125000 },
- { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1137500 },
- { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1137500 },
- { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1150000 },
- { 0, { 0 } }
-};
-
-static struct acpu_level *acpu_freq_tbl_8960_v1[NUM_PVS] __initdata = {
- [PVS_SLOW] = acpu_freq_tbl_8960_kraitv1_slow,
- [PVS_NOM] = acpu_freq_tbl_8960_kraitv1_nom_fast,
- [PVS_FAST] = acpu_freq_tbl_8960_kraitv1_nom_fast,
-};
-
-static struct acpu_level *acpu_freq_tbl_8960_v2[NUM_PVS] __initdata = {
- [PVS_SLOW] = acpu_freq_tbl_8960_kraitv2_slow,
- [PVS_NOM] = acpu_freq_tbl_8960_kraitv2_nom,
- [PVS_FAST] = acpu_freq_tbl_8960_kraitv2_fast,
-};
-
-/* TODO: update the faster table when data is available */
-static struct acpu_level *acpu_freq_tbl_8064[NUM_PVS] __initdata = {
- [PVS_SLOW] = acpu_freq_tbl_8064_slow,
- [PVS_NOM] = acpu_freq_tbl_8064_nom,
- [PVS_FAST] = acpu_freq_tbl_8064_fast,
- [PVS_FASTER] = acpu_freq_tbl_8064_fast,
-};
-
-static struct acpu_level *max_acpu_level;
-
-static unsigned long acpuclk_8960_get_rate(int cpu)
-{
- return scalable[cpu].current_speed->khz;
-}
-
-/* Get the selected source on primary MUX. */
-static int get_pri_clk_src(struct scalable *sc)
-{
- uint32_t regval;
-
- regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
- return regval & 0x3;
-}
-
-/* Set the selected source on primary MUX. */
-static void set_pri_clk_src(struct scalable *sc, uint32_t pri_src_sel)
-{
- uint32_t regval;
-
- regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
- regval &= ~0x3;
- regval |= (pri_src_sel & 0x3);
- set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
- /* Wait for switch to complete. */
- mb();
- udelay(1);
-}
-
-/* Get the selected source on secondary MUX. */
-static int get_sec_clk_src(struct scalable *sc)
-{
- uint32_t regval;
-
- regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
- return (regval >> 2) & 0x3;
-}
-
-/* Set the selected source on secondary MUX. */
-static void set_sec_clk_src(struct scalable *sc, uint32_t sec_src_sel)
-{
- uint32_t regval;
-
- /* Disable secondary source clock gating during switch. */
- regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
- regval |= SECCLKAGD;
- set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
-
- /* Program the MUX. */
- regval &= ~(0x3 << 2);
- regval |= ((sec_src_sel & 0x3) << 2);
- set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
-
- /* Wait for switch to complete. */
- mb();
- udelay(1);
-
- /* Re-enable secondary source clock gating. */
- regval &= ~SECCLKAGD;
- set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
-}
-
-/* Enable an already-configured HFPLL. */
-static void hfpll_enable(struct scalable *sc, bool skip_regulators)
-{
- int rc;
-
- if (!skip_regulators) {
- if (cpu_is_msm8960()) {
- rc = rpm_vreg_set_voltage(
- sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
- sc->vreg[VREG_HFPLL_A].rpm_vreg_voter,
- 2050000,
- sc->vreg[VREG_HFPLL_A].max_vdd, 0);
- if (rc)
- pr_err("%s regulator enable failed (%d)\n",
- sc->vreg[VREG_HFPLL_A].name, rc);
- }
- rc = rpm_vreg_set_voltage(sc->vreg[VREG_HFPLL_B].rpm_vreg_id,
- sc->vreg[VREG_HFPLL_B].rpm_vreg_voter, 1800000,
- sc->vreg[VREG_HFPLL_B].max_vdd, 0);
- if (rc)
- pr_err("%s regulator enable failed (%d)\n",
- sc->vreg[VREG_HFPLL_B].name, rc);
- }
- /* Disable PLL bypass mode. */
- writel_relaxed(0x2, sc->hfpll_base + HFPLL_MODE);
-
- /*
- * H/W requires a 5us delay between disabling the bypass and
- * de-asserting the reset. Delay 10us just to be safe.
- */
- mb();
- udelay(10);
-
- /* De-assert active-low PLL reset. */
- writel_relaxed(0x6, sc->hfpll_base + HFPLL_MODE);
-
- /* Wait for PLL to lock. */
- mb();
- udelay(60);
-
- /* Enable PLL output. */
- writel_relaxed(0x7, sc->hfpll_base + HFPLL_MODE);
-}
-
-/* Disable a HFPLL for power-savings or while its being reprogrammed. */
-static void hfpll_disable(struct scalable *sc, bool skip_regulators)
-{
- int rc;
-
- /*
- * Disable the PLL output, disable test mode, enable
- * the bypass mode, and assert the reset.
- */
- writel_relaxed(0, sc->hfpll_base + HFPLL_MODE);
-
- if (!skip_regulators) {
- rc = rpm_vreg_set_voltage(sc->vreg[VREG_HFPLL_B].rpm_vreg_id,
- sc->vreg[VREG_HFPLL_B].rpm_vreg_voter, 0,
- 0, 0);
- if (rc)
- pr_err("%s regulator enable failed (%d)\n",
- sc->vreg[VREG_HFPLL_B].name, rc);
-
- if (cpu_is_msm8960()) {
- rc = rpm_vreg_set_voltage(
- sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
- sc->vreg[VREG_HFPLL_A].rpm_vreg_voter,
- 0, 0, 0);
- if (rc)
- pr_err("%s regulator enable failed (%d)\n",
- sc->vreg[VREG_HFPLL_A].name, rc);
- }
- }
-}
-
-/* Program the HFPLL rate. Assumes HFPLL is already disabled. */
-static void hfpll_set_rate(struct scalable *sc, struct core_speed *tgt_s)
-{
- writel_relaxed(tgt_s->pll_l_val, sc->hfpll_base + HFPLL_L_VAL);
-}
-
-/* Return the L2 speed that should be applied. */
-static struct l2_level *compute_l2_level(struct scalable *sc,
- struct l2_level *vote_l)
-{
- struct l2_level *new_l;
- int cpu;
-
- /* Bounds check. */
- BUG_ON(vote_l >= (l2_freq_tbl + l2_freq_tbl_size));
-
- /* Find max L2 speed vote. */
- sc->l2_vote = vote_l;
- new_l = l2_freq_tbl;
- for_each_present_cpu(cpu)
- new_l = max(new_l, scalable[cpu].l2_vote);
-
- return new_l;
-}
-
-/* Update the bus bandwidth request. */
-static void set_bus_bw(unsigned int bw)
-{
- int ret;
-
- /* Bounds check. */
- if (bw >= ARRAY_SIZE(bw_level_tbl)) {
- pr_err("invalid bandwidth request (%d)\n", bw);
- return;
- }
-
- /* Update bandwidth if request has changed. This may sleep. */
- ret = msm_bus_scale_client_update_request(bus_perf_client, bw);
- if (ret)
- pr_err("bandwidth request failed (%d)\n", ret);
-}
-
-/* Set the CPU or L2 clock speed. */
-static void set_speed(struct scalable *sc, struct core_speed *tgt_s,
- enum setrate_reason reason)
-{
- struct core_speed *strt_s = sc->current_speed;
-
- if (tgt_s == strt_s)
- return;
-
- if (strt_s->src == HFPLL && tgt_s->src == HFPLL) {
- /*
- * Move to an always-on source running at a frequency that does
- * not require an elevated CPU voltage. PLL8 is used here.
- */
- set_sec_clk_src(sc, SEC_SRC_SEL_AUX);
- set_pri_clk_src(sc, PRI_SRC_SEL_SEC_SRC);
-
- /* Program CPU HFPLL. */
- hfpll_disable(sc, 1);
- hfpll_set_rate(sc, tgt_s);
- hfpll_enable(sc, 1);
-
- /* Move CPU to HFPLL source. */
- set_pri_clk_src(sc, tgt_s->pri_src_sel);
- } else if (strt_s->src == HFPLL && tgt_s->src != HFPLL) {
- /*
- * If responding to CPU_DEAD we must be running on another CPU.
- * Therefore, we can't access the downed CPU's clock MUX CP15
- * registers from here and can't change clock sources. If the
- * CPU is collapsed, however, it is still safe to turn off the
- * PLL without switching the MUX away from it.
- */
- if (reason != SETRATE_HOTPLUG || sc == &scalable[L2]) {
- set_sec_clk_src(sc, tgt_s->sec_src_sel);
- set_pri_clk_src(sc, tgt_s->pri_src_sel);
- hfpll_disable(sc, 0);
- } else if (reason == SETRATE_HOTPLUG
- && msm_pm_verify_cpu_pc(SCALABLE_TO_CPU(sc))) {
- hfpll_disable(sc, 0);
- }
- } else if (strt_s->src != HFPLL && tgt_s->src == HFPLL) {
- /*
- * If responding to CPU_UP_PREPARE, we can't change CP15
- * registers for the CPU that's coming up since we're not
- * running on that CPU. That's okay though, since the MUX
- * source was not changed on the way down, either.
- */
- if (reason != SETRATE_HOTPLUG || sc == &scalable[L2]) {
- hfpll_set_rate(sc, tgt_s);
- hfpll_enable(sc, 0);
- set_pri_clk_src(sc, tgt_s->pri_src_sel);
- } else if (reason == SETRATE_HOTPLUG
- && msm_pm_verify_cpu_pc(SCALABLE_TO_CPU(sc))) {
- /* PLL was disabled during hot-unplug. Re-enable it. */
- hfpll_set_rate(sc, tgt_s);
- hfpll_enable(sc, 0);
- }
- } else {
- if (reason != SETRATE_HOTPLUG || sc == &scalable[L2])
- set_sec_clk_src(sc, tgt_s->sec_src_sel);
- }
-
- sc->current_speed = tgt_s;
-}
-
-/* Apply any per-cpu voltage increases. */
-static int increase_vdd(int cpu, unsigned int vdd_core, unsigned int vdd_mem,
- unsigned int vdd_dig, enum setrate_reason reason)
-{
- struct scalable *sc = &scalable[cpu];
- int rc = 0;
-
- /*
- * Increase vdd_mem active-set before vdd_dig.
- * vdd_mem should be >= vdd_dig.
- */
- if (vdd_mem > sc->vreg[VREG_MEM].cur_vdd) {
- rc = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
- sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
- sc->vreg[VREG_MEM].max_vdd, 0);
- if (rc) {
- pr_err("%s increase failed (%d)\n",
- sc->vreg[VREG_MEM].name, rc);
- return rc;
- }
- sc->vreg[VREG_MEM].cur_vdd = vdd_mem;
- }
-
- /* Increase vdd_dig active-set vote. */
- if (vdd_dig > sc->vreg[VREG_DIG].cur_vdd) {
- rc = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
- sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
- sc->vreg[VREG_DIG].max_vdd, 0);
- if (rc) {
- pr_err("%s increase failed (%d)\n",
- sc->vreg[VREG_DIG].name, rc);
- return rc;
- }
- sc->vreg[VREG_DIG].cur_vdd = vdd_dig;
- }
-
- /*
- * Update per-CPU core voltage. Don't do this for the hotplug path for
- * which it should already be correct. Attempting to set it is bad
- * because we don't know what CPU we are running on at this point, but
- * the CPU regulator API requires we call it from the affected CPU.
- */
- if (vdd_core > sc->vreg[VREG_CORE].cur_vdd
- && reason != SETRATE_HOTPLUG) {
- rc = regulator_set_voltage(sc->vreg[VREG_CORE].reg, vdd_core,
- sc->vreg[VREG_CORE].max_vdd);
- if (rc) {
- pr_err("%s increase failed (%d)\n",
- sc->vreg[VREG_CORE].name, rc);
- return rc;
- }
- sc->vreg[VREG_CORE].cur_vdd = vdd_core;
- }
-
- return rc;
-}
-
-/* Apply any per-cpu voltage decreases. */
-static void decrease_vdd(int cpu, unsigned int vdd_core, unsigned int vdd_mem,
- unsigned int vdd_dig, enum setrate_reason reason)
-{
- struct scalable *sc = &scalable[cpu];
- int ret;
-
- /*
- * Update per-CPU core voltage. This must be called on the CPU
- * that's being affected. Don't do this in the hotplug remove path,
- * where the rail is off and we're executing on the other CPU.
- */
- if (vdd_core < sc->vreg[VREG_CORE].cur_vdd
- && reason != SETRATE_HOTPLUG) {
- ret = regulator_set_voltage(sc->vreg[VREG_CORE].reg, vdd_core,
- sc->vreg[VREG_CORE].max_vdd);
- if (ret) {
- pr_err("%s decrease failed (%d)\n",
- sc->vreg[VREG_CORE].name, ret);
- return;
- }
- sc->vreg[VREG_CORE].cur_vdd = vdd_core;
- }
-
- /* Decrease vdd_dig active-set vote. */
- if (vdd_dig < sc->vreg[VREG_DIG].cur_vdd) {
- ret = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
- sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
- sc->vreg[VREG_DIG].max_vdd, 0);
- if (ret) {
- pr_err("%s decrease failed (%d)\n",
- sc->vreg[VREG_DIG].name, ret);
- return;
- }
- sc->vreg[VREG_DIG].cur_vdd = vdd_dig;
- }
-
- /*
- * Decrease vdd_mem active-set after vdd_dig.
- * vdd_mem should be >= vdd_dig.
- */
- if (vdd_mem < sc->vreg[VREG_MEM].cur_vdd) {
- ret = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
- sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
- sc->vreg[VREG_MEM].max_vdd, 0);
- if (ret) {
- pr_err("%s decrease failed (%d)\n",
- sc->vreg[VREG_MEM].name, ret);
- return;
- }
- sc->vreg[VREG_MEM].cur_vdd = vdd_mem;
- }
-}
-
-static unsigned int calculate_vdd_mem(struct acpu_level *tgt)
-{
- return tgt->l2_level->vdd_mem;
-}
-
-static unsigned int calculate_vdd_dig(struct acpu_level *tgt)
-{
- unsigned int pll_vdd_dig;
-
- if (tgt->l2_level->speed.src != HFPLL)
- pll_vdd_dig = scalable[L2].hfpll_vdd_tbl[HFPLL_VDD_NONE];
- else if (tgt->l2_level->speed.pll_l_val > HFPLL_LOW_VDD_PLL_L_MAX)
- pll_vdd_dig = scalable[L2].hfpll_vdd_tbl[HFPLL_VDD_NOM];
- else
- pll_vdd_dig = scalable[L2].hfpll_vdd_tbl[HFPLL_VDD_LOW];
-
- return max(tgt->l2_level->vdd_dig, pll_vdd_dig);
-}
-
-static unsigned int calculate_vdd_core(struct acpu_level *tgt)
-{
- return tgt->vdd_core;
-}
-
-/* Set the CPU's clock rate and adjust the L2 rate, if appropriate. */
-static int acpuclk_8960_set_rate(int cpu, unsigned long rate,
- enum setrate_reason reason)
-{
- struct core_speed *strt_acpu_s, *tgt_acpu_s;
- struct l2_level *tgt_l2_l;
- struct acpu_level *tgt;
- unsigned int vdd_mem, vdd_dig, vdd_core;
- unsigned long flags;
- int rc = 0;
-
- if (cpu > num_possible_cpus())
- return -EINVAL;
-
- if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG)
- mutex_lock(&driver_lock);
-
- strt_acpu_s = scalable[cpu].current_speed;
-
- /* Return early if rate didn't change. */
- if (rate == strt_acpu_s->khz)
- goto out;
-
- /* Find target frequency. */
- for (tgt = acpu_freq_tbl; tgt->speed.khz != 0; tgt++) {
- if (tgt->speed.khz == rate) {
- tgt_acpu_s = &tgt->speed;
- break;
- }
- }
- if (tgt->speed.khz == 0) {
- rc = -EINVAL;
- goto out;
- }
-
- /* Calculate voltage requirements for the current CPU. */
- vdd_mem = calculate_vdd_mem(tgt);
- vdd_dig = calculate_vdd_dig(tgt);
- vdd_core = calculate_vdd_core(tgt);
-
- /* Increase VDD levels if needed. */
- if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG) {
- rc = increase_vdd(cpu, vdd_core, vdd_mem, vdd_dig, reason);
- if (rc)
- goto out;
- }
-
- pr_debug("Switching from ACPU%d rate %u KHz -> %u KHz\n",
- cpu, strt_acpu_s->khz, tgt_acpu_s->khz);
-
- /* Set the CPU speed. */
- set_speed(&scalable[cpu], tgt_acpu_s, reason);
-
- /*
- * Update the L2 vote and apply the rate change. A spinlock is
- * necessary to ensure L2 rate is calulated and set atomically,
- * even if acpuclk_8960_set_rate() is called from an atomic context
- * and the driver_lock mutex is not acquired.
- */
- spin_lock_irqsave(&l2_lock, flags);
- tgt_l2_l = compute_l2_level(&scalable[cpu], tgt->l2_level);
- set_speed(&scalable[L2], &tgt_l2_l->speed, reason);
- spin_unlock_irqrestore(&l2_lock, flags);
-
- /* Nothing else to do for power collapse or SWFI. */
- if (reason == SETRATE_PC || reason == SETRATE_SWFI)
- goto out;
-
- /* Update bus bandwith request. */
- set_bus_bw(tgt_l2_l->bw_level);
-
- /* Drop VDD levels if we can. */
- decrease_vdd(cpu, vdd_core, vdd_mem, vdd_dig, reason);
-
- pr_debug("ACPU%d speed change complete\n", cpu);
-
-out:
- if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG)
- mutex_unlock(&driver_lock);
- return rc;
-}
-
-/* Initialize a HFPLL at a given rate and enable it. */
-static void __cpuinit hfpll_init(struct scalable *sc, struct core_speed *tgt_s)
-{
- pr_debug("Initializing HFPLL%d\n", sc - scalable);
-
- /* Disable the PLL for re-programming. */
- hfpll_disable(sc, 1);
-
- /* Configure PLL parameters for integer mode. */
- writel_relaxed(0x7845C665, sc->hfpll_base + HFPLL_CONFIG_CTL);
- writel_relaxed(0, sc->hfpll_base + HFPLL_M_VAL);
- writel_relaxed(1, sc->hfpll_base + HFPLL_N_VAL);
-
- /* Program droop controller. */
- writel_relaxed(0x0108C000, sc->hfpll_base + HFPLL_DROOP_CTL);
-
- /* Set an initial rate and enable the PLL. */
- hfpll_set_rate(sc, tgt_s);
- hfpll_enable(sc, 0);
-}
-
-/* Voltage regulator initialization. */
-static void __cpuinit regulator_init(int cpu, struct acpu_level *lvl)
-{
- int ret;
- struct scalable *sc = &scalable[cpu];
- unsigned int vdd_mem, vdd_dig, vdd_core;
-
- vdd_mem = calculate_vdd_mem(lvl);
- vdd_dig = calculate_vdd_dig(lvl);
-
- /* Set initial vdd_mem vote. */
- ret = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
- sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
- sc->vreg[VREG_MEM].max_vdd, 0);
- if (ret) {
- pr_err("%s initialization failed (%d)\n",
- sc->vreg[VREG_MEM].name, ret);
- BUG();
- }
- sc->vreg[VREG_MEM].cur_vdd = vdd_mem;
-
- /* Set initial vdd_dig vote. */
- ret = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
- sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
- sc->vreg[VREG_DIG].max_vdd, 0);
- if (ret) {
- pr_err("%s initialization failed (%d)\n",
- sc->vreg[VREG_DIG].name, ret);
- BUG();
- }
- sc->vreg[VREG_DIG].cur_vdd = vdd_dig;
-
- /* Setup Krait CPU regulators and initial core voltage. */
- sc->vreg[VREG_CORE].reg = regulator_get(NULL,
- sc->vreg[VREG_CORE].name);
- if (IS_ERR(sc->vreg[VREG_CORE].reg)) {
- pr_err("regulator_get(%s) failed (%ld)\n",
- sc->vreg[VREG_CORE].name,
- PTR_ERR(sc->vreg[VREG_CORE].reg));
- BUG();
- }
- vdd_core = calculate_vdd_core(lvl);
- ret = regulator_set_voltage(sc->vreg[VREG_CORE].reg, vdd_core,
- sc->vreg[VREG_CORE].max_vdd);
- if (ret) {
- pr_err("%s initialization failed (%d)\n",
- sc->vreg[VREG_CORE].name, ret);
- BUG();
- }
- sc->vreg[VREG_CORE].cur_vdd = vdd_core;
- ret = regulator_enable(sc->vreg[VREG_CORE].reg);
- if (ret) {
- pr_err("regulator_enable(%s) failed (%d)\n",
- sc->vreg[VREG_CORE].name, ret);
- BUG();
- }
- sc->regulators_initialized = true;
-}
-
-/* Set initial rate for a given core. */
-static void __cpuinit init_clock_sources(struct scalable *sc,
- struct core_speed *tgt_s)
-{
- uint32_t regval;
-
- /* Select PLL8 as AUX source input to the secondary MUX. */
- writel_relaxed(0x3, sc->aux_clk_sel);
-
- /* Switch away from the HFPLL while it's re-initialized. */
- set_sec_clk_src(sc, SEC_SRC_SEL_AUX);
- set_pri_clk_src(sc, PRI_SRC_SEL_SEC_SRC);
- hfpll_init(sc, tgt_s);
-
- /* Set PRI_SRC_SEL_HFPLL_DIV2 divider to div-2. */
- regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
- regval &= ~(0x3 << 6);
- set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
-
- /* Switch to the target clock source. */
- set_sec_clk_src(sc, tgt_s->sec_src_sel);
- set_pri_clk_src(sc, tgt_s->pri_src_sel);
- sc->current_speed = tgt_s;
-}
-
-static void __cpuinit per_cpu_init(void *data)
-{
- int cpu = smp_processor_id();
-
- init_clock_sources(&scalable[cpu], &max_acpu_level->speed);
- scalable[cpu].l2_vote = max_acpu_level->l2_level;
- scalable[cpu].clocks_initialized = true;
-}
-
-/* Register with bus driver. */
-static void __init bus_init(unsigned int init_bw)
-{
- int ret;
-
- bus_perf_client = msm_bus_scale_register_client(&bus_client_pdata);
- if (!bus_perf_client) {
- pr_err("unable to register bus client\n");
- BUG();
- }
-
- ret = msm_bus_scale_client_update_request(bus_perf_client, init_bw);
- if (ret)
- pr_err("initial bandwidth request failed (%d)\n", ret);
-}
-
-#ifdef CONFIG_CPU_FREQ_MSM
-static struct cpufreq_frequency_table freq_table[NR_CPUS][30];
-
-static void __init cpufreq_table_init(void)
-{
- int cpu;
-
- for_each_possible_cpu(cpu) {
- int i, freq_cnt = 0;
- /* Construct the freq_table tables from acpu_freq_tbl. */
- for (i = 0; acpu_freq_tbl[i].speed.khz != 0
- && freq_cnt < ARRAY_SIZE(*freq_table); i++) {
- if (acpu_freq_tbl[i].use_for_scaling) {
- freq_table[cpu][freq_cnt].index = freq_cnt;
- freq_table[cpu][freq_cnt].frequency
- = acpu_freq_tbl[i].speed.khz;
- freq_cnt++;
- }
- }
- /* freq_table not big enough to store all usable freqs. */
- BUG_ON(acpu_freq_tbl[i].speed.khz != 0);
-
- freq_table[cpu][freq_cnt].index = freq_cnt;
- freq_table[cpu][freq_cnt].frequency = CPUFREQ_TABLE_END;
-
- pr_info("CPU%d: %d scaling frequencies supported.\n",
- cpu, freq_cnt);
-
- /* Register table with CPUFreq. */
- cpufreq_frequency_table_get_attr(freq_table[cpu], cpu);
- }
-}
-#else
-static void __init cpufreq_table_init(void) {}
-#endif
-
-#define HOT_UNPLUG_KHZ STBY_KHZ
-static int __cpuinit acpuclock_cpu_callback(struct notifier_block *nfb,
- unsigned long action, void *hcpu)
-{
- static int prev_khz[NR_CPUS];
- static int prev_pri_src[NR_CPUS];
- static int prev_sec_src[NR_CPUS];
- int cpu = (int)hcpu;
-
- switch (action) {
- case CPU_DYING:
- case CPU_DYING_FROZEN:
- /*
- * On Krait v1 and 8064v1, the primary and secondary muxes must
- * be set to QSB before L2 power collapse and restored after.
- */
- if (cpu_is_krait_v1() || cpu_is_apq8064()) {
- prev_sec_src[cpu] = get_sec_clk_src(&scalable[cpu]);
- prev_pri_src[cpu] = get_pri_clk_src(&scalable[cpu]);
- set_sec_clk_src(&scalable[cpu], SEC_SRC_SEL_QSB);
- set_pri_clk_src(&scalable[cpu], PRI_SRC_SEL_SEC_SRC);
- }
- break;
- case CPU_DEAD:
- case CPU_DEAD_FROZEN:
- prev_khz[cpu] = acpuclk_8960_get_rate(cpu);
- /* Fall through. */
- case CPU_UP_CANCELED:
- case CPU_UP_CANCELED_FROZEN:
- if (scalable[cpu].clocks_initialized)
- acpuclk_8960_set_rate(cpu, HOT_UNPLUG_KHZ,
- SETRATE_HOTPLUG);
- break;
- case CPU_UP_PREPARE:
- case CPU_UP_PREPARE_FROZEN:
- if (scalable[cpu].clocks_initialized)
- acpuclk_8960_set_rate(cpu, prev_khz[cpu],
- SETRATE_HOTPLUG);
- if (!scalable[cpu].regulators_initialized)
- regulator_init(cpu, max_acpu_level);
- break;
- case CPU_STARTING:
- case CPU_STARTING_FROZEN:
- if (!scalable[cpu].clocks_initialized) {
- per_cpu_init(NULL);
- } else if (cpu_is_krait_v1() || cpu_is_apq8064()) {
- set_sec_clk_src(&scalable[cpu], prev_sec_src[cpu]);
- set_pri_clk_src(&scalable[cpu], prev_pri_src[cpu]);
- }
- break;
- default:
- break;
- }
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block __cpuinitdata acpuclock_cpu_notifier = {
- .notifier_call = acpuclock_cpu_callback,
-};
-
-static const int krait_needs_vmin(void)
-{
- switch (read_cpuid_id()) {
- case 0x511F04D0:
- case 0x511F04D1:
- case 0x510F06F0:
- return 1;
- default:
- return 0;
- };
-}
-
-static void kraitv2_apply_vmin(struct acpu_level *tbl)
-{
- for (; tbl->speed.khz != 0; tbl++)
- if (tbl->vdd_core < 1150000)
- tbl->vdd_core = 1150000;
-}
-
-static enum pvs __init get_pvs(void)
-{
- uint32_t pte_efuse, pvs;
-
- pte_efuse = readl_relaxed(QFPROM_PTE_EFUSE_ADDR);
- pvs = (pte_efuse >> 10) & 0x7;
- if (pvs == 0x7)
- pvs = (pte_efuse >> 13) & 0x7;
-
- switch (pvs) {
- case 0x0:
- case 0x7:
- pr_info("ACPU PVS: Slow\n");
- return PVS_SLOW;
- case 0x1:
- pr_info("ACPU PVS: Nominal\n");
- return PVS_NOM;
- case 0x3:
- pr_info("ACPU PVS: Fast\n");
- return PVS_FAST;
- case 0x4:
- if (cpu_is_apq8064()) {
- pr_info("ACPU PVS: Faster\n");
- return PVS_FASTER;
- }
- default:
- pr_warn("ACPU PVS: Unknown. Defaulting to slow\n");
- return PVS_SLOW;
- }
-}
-
-static void __init select_freq_plan(void)
-{
- struct acpu_level *l;
-
- /* Select frequency tables. */
- if (cpu_is_msm8960()) {
- enum pvs pvs_id = get_pvs();
-
- scalable = scalable_8960;
- if (cpu_is_krait_v1()) {
- acpu_freq_tbl = acpu_freq_tbl_8960_v1[pvs_id];
- l2_freq_tbl = l2_freq_tbl_8960_kraitv1;
- l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8960_kraitv1);
- } else {
- acpu_freq_tbl = acpu_freq_tbl_8960_v2[pvs_id];
- l2_freq_tbl = l2_freq_tbl_8960_kraitv2;
- l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8960_kraitv2);
- }
- } else if (cpu_is_apq8064()) {
- enum pvs pvs_id = get_pvs();
-
- scalable = scalable_8064;
- acpu_freq_tbl = acpu_freq_tbl_8064[pvs_id];
- l2_freq_tbl = l2_freq_tbl_8064;
- l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8064);
- } else {
- BUG();
- }
- BUG_ON(!acpu_freq_tbl);
- if (krait_needs_vmin())
- kraitv2_apply_vmin(acpu_freq_tbl);
-
- /* Find the max supported scaling frequency. */
- for (l = acpu_freq_tbl; l->speed.khz != 0; l++)
- if (l->use_for_scaling)
- max_acpu_level = l;
- BUG_ON(!max_acpu_level);
- pr_info("Max ACPU freq: %u KHz\n", max_acpu_level->speed.khz);
-}
-
-static struct acpuclk_data acpuclk_8960_data = {
- .set_rate = acpuclk_8960_set_rate,
- .get_rate = acpuclk_8960_get_rate,
- .power_collapse_khz = STBY_KHZ,
- .wait_for_irq_khz = STBY_KHZ,
+static struct acpuclk_krait_params acpuclk_8960_params __initdata = {
+ .scalable = scalable,
+ .scalable_size = sizeof(scalable),
+ .hfpll_data = &hfpll_data,
+ .pvs_tables = pvs_tables,
+ .l2_freq_tbl = l2_freq_tbl,
+ .l2_freq_tbl_size = sizeof(l2_freq_tbl),
+ .bus_scale = &bus_scale_data,
+ .qfprom_phys_base = 0x00700000,
};
static int __init acpuclk_8960_probe(struct platform_device *pdev)
{
- int cpu;
-
- select_freq_plan();
-
- for_each_online_cpu(cpu)
- regulator_init(cpu, max_acpu_level);
- bus_init(max_acpu_level->l2_level->bw_level);
-
- init_clock_sources(&scalable[L2], &max_acpu_level->l2_level->speed);
- on_each_cpu(per_cpu_init, NULL, true);
-
- cpufreq_table_init();
-
- acpuclk_register(&acpuclk_8960_data);
- register_hotcpu_notifier(&acpuclock_cpu_notifier);
-
- return 0;
+ return acpuclk_krait_init(&pdev->dev, &acpuclk_8960_params);
}
static struct platform_driver acpuclk_8960_driver = {
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index 8cf9c2b..9ed038b 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -28,21 +28,7 @@
#define LVL_NOM RPM_REGULATOR_CORNER_NORMAL
#define LVL_HIGH RPM_REGULATOR_CORNER_SUPER_TURBO
-static struct hfpll_data hfpll_data_cpu = {
- .mode_offset = 0x00,
- .l_offset = 0x04,
- .m_offset = 0x08,
- .n_offset = 0x0C,
- .config_offset = 0x14,
- /* TODO: Verify magic number for 8974 when available. */
- .config_val = 0x7845C665,
- .low_vdd_l_max = 52,
- .vdd[HFPLL_VDD_NONE] = 0,
- .vdd[HFPLL_VDD_LOW] = 810000,
- .vdd[HFPLL_VDD_NOM] = 900000,
-};
-
-static struct hfpll_data hfpll_data_l2 = {
+static struct hfpll_data hfpll_data __initdata = {
.mode_offset = 0x00,
.l_offset = 0x04,
.m_offset = 0x08,
@@ -56,10 +42,9 @@
.vdd[HFPLL_VDD_NOM] = LVL_NOM,
};
-static struct scalable scalable[] = {
+static struct scalable scalable[] __initdata = {
[CPU0] = {
.hfpll_phys_base = 0xF908A000,
- .hfpll_data = &hfpll_data_cpu,
.l2cpmr_iaddr = 0x4501,
.vreg[VREG_CORE] = { "krait0", 1050000, 3200000 },
.vreg[VREG_MEM] = { "krait0_mem", 1050000 },
@@ -69,7 +54,6 @@
},
[CPU1] = {
.hfpll_phys_base = 0xF909A000,
- .hfpll_data = &hfpll_data_cpu,
.l2cpmr_iaddr = 0x5501,
.vreg[VREG_CORE] = { "krait1", 1050000, 3200000 },
.vreg[VREG_MEM] = { "krait1_mem", 1050000 },
@@ -79,7 +63,6 @@
},
[CPU2] = {
.hfpll_phys_base = 0xF90AA000,
- .hfpll_data = &hfpll_data_cpu,
.l2cpmr_iaddr = 0x6501,
.vreg[VREG_CORE] = { "krait2", 1050000, 3200000 },
.vreg[VREG_MEM] = { "krait2_mem", 1050000 },
@@ -89,7 +72,6 @@
},
[CPU3] = {
.hfpll_phys_base = 0xF90BA000,
- .hfpll_data = &hfpll_data_cpu,
.l2cpmr_iaddr = 0x7501,
.vreg[VREG_CORE] = { "krait3", 1050000, 3200000 },
.vreg[VREG_MEM] = { "krait3_mem", 1050000 },
@@ -99,14 +81,13 @@
},
[L2] = {
.hfpll_phys_base = 0xF9016000,
- .hfpll_data = &hfpll_data_l2,
.l2cpmr_iaddr = 0x0500,
.vreg[VREG_HFPLL_A] = { "l2_hfpll_a", 2150000 },
.vreg[VREG_HFPLL_B] = { "l2_hfpll_b", 1800000 },
},
};
-static struct msm_bus_paths bw_level_tbl[] = {
+static struct msm_bus_paths bw_level_tbl[] __initdata = {
[0] = BW_MBPS(400), /* At least 50 MHz on bus. */
[1] = BW_MBPS(800), /* At least 100 MHz on bus. */
[2] = BW_MBPS(1334), /* At least 167 MHz on bus. */
@@ -114,15 +95,14 @@
[4] = BW_MBPS(3200), /* At least 333 MHz on bus. */
};
-static struct msm_bus_scale_pdata bus_scale_data = {
+static struct msm_bus_scale_pdata bus_scale_data __initdata = {
.usecase = bw_level_tbl,
.num_usecases = ARRAY_SIZE(bw_level_tbl),
.active_only = 1,
.name = "acpuclk-8974",
};
-#define L2(x) (&l2_freq_tbl[(x)])
-static struct l2_level l2_freq_tbl[] = {
+static struct l2_level l2_freq_tbl[] __initdata = {
[0] = { {STBY_KHZ, QSB, 0, 0, 0 }, LVL_LOW, 1050000, 0 },
[1] = { { 300000, PLL_0, 0, 2, 0 }, LVL_LOW, 1050000, 2 },
[2] = { { 384000, HFPLL, 2, 0, 40 }, LVL_NOM, 1050000, 2 },
@@ -137,7 +117,7 @@
[11] = { { 1036800, HFPLL, 1, 0, 54 }, LVL_NOM, 1050000, 4 },
};
-static struct acpu_level acpu_freq_tbl[] = {
+static struct acpu_level acpu_freq_tbl[] __initdata = {
{ 0, {STBY_KHZ, QSB, 0, 0, 0 }, L2(0), 1050000 },
{ 1, { 300000, PLL_0, 0, 2, 0 }, L2(1), 1050000 },
{ 1, { 384000, HFPLL, 2, 0, 40 }, L2(2), 1050000 },
@@ -153,14 +133,20 @@
{ 0, { 0 } }
};
-static struct acpuclk_krait_params acpuclk_8974_params = {
+static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
+ [PVS_SLOW] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
+ [PVS_NOMINAL] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
+ [PVS_FAST] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
+};
+
+static struct acpuclk_krait_params acpuclk_8974_params __initdata = {
.scalable = scalable,
- .pvs_acpu_freq_tbl[PVS_SLOW] = acpu_freq_tbl,
- .pvs_acpu_freq_tbl[PVS_NOMINAL] = acpu_freq_tbl,
- .pvs_acpu_freq_tbl[PVS_FAST] = acpu_freq_tbl,
+ .scalable_size = sizeof(scalable),
+ .hfpll_data = &hfpll_data,
+ .pvs_tables = pvs_tables,
.l2_freq_tbl = l2_freq_tbl,
- .l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl),
- .bus_scale_data = &bus_scale_data,
+ .l2_freq_tbl_size = sizeof(l2_freq_tbl),
+ .bus_scale = &bus_scale_data,
.qfprom_phys_base = 0xFC4A8000,
};
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index 8bd54e3..fd43f57 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -57,7 +57,9 @@
const struct acpu_level *max_acpu_lvl;
const struct l2_level *l2_freq_tbl;
struct scalable *scalable;
+ struct hfpll_data *hfpll_data;
u32 bus_perf_client;
+ struct msm_bus_scale_pdata *bus_scale;
struct device *dev;
} drv;
@@ -130,7 +132,7 @@
}
/* Disable PLL bypass mode. */
- writel_relaxed(0x2, sc->hfpll_base + sc->hfpll_data->mode_offset);
+ writel_relaxed(0x2, sc->hfpll_base + drv.hfpll_data->mode_offset);
/*
* H/W requires a 5us delay between disabling the bypass and
@@ -140,14 +142,14 @@
udelay(10);
/* De-assert active-low PLL reset. */
- writel_relaxed(0x6, sc->hfpll_base + sc->hfpll_data->mode_offset);
+ writel_relaxed(0x6, sc->hfpll_base + drv.hfpll_data->mode_offset);
/* Wait for PLL to lock. */
mb();
udelay(60);
/* Enable PLL output. */
- writel_relaxed(0x7, sc->hfpll_base + sc->hfpll_data->mode_offset);
+ writel_relaxed(0x7, sc->hfpll_base + drv.hfpll_data->mode_offset);
}
/* Disable a HFPLL for power-savings or while it's being reprogrammed. */
@@ -157,7 +159,7 @@
* Disable the PLL output, disable test mode, enable the bypass mode,
* and assert the reset.
*/
- writel_relaxed(0, sc->hfpll_base + sc->hfpll_data->mode_offset);
+ writel_relaxed(0, sc->hfpll_base + drv.hfpll_data->mode_offset);
if (!skip_regulators) {
/* Remove voltage votes required by the HFPLL. */
@@ -170,19 +172,17 @@
static void hfpll_set_rate(struct scalable *sc, const struct core_speed *tgt_s)
{
writel_relaxed(tgt_s->pll_l_val,
- sc->hfpll_base + sc->hfpll_data->l_offset);
+ sc->hfpll_base + drv.hfpll_data->l_offset);
}
/* Return the L2 speed that should be applied. */
-static const struct l2_level *compute_l2_level(struct scalable *sc,
- const struct l2_level *vote_l)
+static unsigned int compute_l2_level(struct scalable *sc, unsigned int vote_l)
{
- const struct l2_level *new_l;
+ unsigned int new_l = 0;
int cpu;
/* Find max L2 speed vote. */
sc->l2_vote = vote_l;
- new_l = drv.l2_freq_tbl;
for_each_present_cpu(cpu)
new_l = max(new_l, drv.scalable[cpu].l2_vote);
@@ -350,23 +350,23 @@
static int calculate_vdd_mem(const struct acpu_level *tgt)
{
- return tgt->l2_level->vdd_mem;
+ return drv.l2_freq_tbl[tgt->l2_level].vdd_mem;
}
static int calculate_vdd_dig(const struct acpu_level *tgt)
{
int pll_vdd_dig;
- const int *hfpll_vdd = drv.scalable[L2].hfpll_data->vdd;
- const u32 low_vdd_l_max = drv.scalable[L2].hfpll_data->low_vdd_l_max;
+ const int *hfpll_vdd = drv.hfpll_data->vdd;
+ const u32 low_vdd_l_max = drv.hfpll_data->low_vdd_l_max;
- if (tgt->l2_level->speed.src != HFPLL)
+ if (drv.l2_freq_tbl[tgt->l2_level].speed.src != HFPLL)
pll_vdd_dig = hfpll_vdd[HFPLL_VDD_NONE];
- else if (tgt->l2_level->speed.pll_l_val > low_vdd_l_max)
+ else if (drv.l2_freq_tbl[tgt->l2_level].speed.pll_l_val > low_vdd_l_max)
pll_vdd_dig = hfpll_vdd[HFPLL_VDD_NOM];
else
pll_vdd_dig = hfpll_vdd[HFPLL_VDD_LOW];
- return max(tgt->l2_level->vdd_dig, pll_vdd_dig);
+ return max(drv.l2_freq_tbl[tgt->l2_level].vdd_dig, pll_vdd_dig);
}
static int calculate_vdd_core(const struct acpu_level *tgt)
@@ -379,8 +379,8 @@
enum setrate_reason reason)
{
const struct core_speed *strt_acpu_s, *tgt_acpu_s;
- const struct l2_level *tgt_l2_l;
const struct acpu_level *tgt;
+ int tgt_l2_l;
int vdd_mem, vdd_dig, vdd_core;
unsigned long flags;
int rc = 0;
@@ -436,7 +436,7 @@
*/
spin_lock_irqsave(&l2_lock, flags);
tgt_l2_l = compute_l2_level(&drv.scalable[cpu], tgt->l2_level);
- set_speed(&drv.scalable[L2], &tgt_l2_l->speed);
+ set_speed(&drv.scalable[L2], &drv.l2_freq_tbl[tgt_l2_l].speed);
spin_unlock_irqrestore(&l2_lock, flags);
/* Nothing else to do for power collapse or SWFI. */
@@ -444,7 +444,7 @@
goto out;
/* Update bus bandwith request. */
- set_bus_bw(tgt_l2_l->bw_level);
+ set_bus_bw(drv.l2_freq_tbl[tgt_l2_l].bw_level);
/* Drop VDD levels if we can. */
decrease_vdd(cpu, vdd_core, vdd_mem, vdd_dig, reason);
@@ -467,15 +467,15 @@
hfpll_disable(sc, true);
/* Configure PLL parameters for integer mode. */
- writel_relaxed(sc->hfpll_data->config_val,
- sc->hfpll_base + sc->hfpll_data->config_offset);
- writel_relaxed(0, sc->hfpll_base + sc->hfpll_data->m_offset);
- writel_relaxed(1, sc->hfpll_base + sc->hfpll_data->n_offset);
+ writel_relaxed(drv.hfpll_data->config_val,
+ sc->hfpll_base + drv.hfpll_data->config_offset);
+ writel_relaxed(0, sc->hfpll_base + drv.hfpll_data->m_offset);
+ writel_relaxed(1, sc->hfpll_base + drv.hfpll_data->n_offset);
/* Program droop controller, if supported */
- if (sc->hfpll_data->has_droop_ctl)
- writel_relaxed(sc->hfpll_data->droop_val,
- sc->hfpll_base + sc->hfpll_data->droop_offset);
+ if (drv.hfpll_data->has_droop_ctl)
+ writel_relaxed(drv.hfpll_data->droop_val,
+ sc->hfpll_base + drv.hfpll_data->droop_offset);
/* Set an initial rate and enable the PLL. */
hfpll_set_rate(sc, tgt_s);
@@ -679,18 +679,18 @@
}
/* Register with bus driver. */
-static void __init bus_init(struct msm_bus_scale_pdata *bus_scale_data)
+static void __init bus_init(void)
{
int ret;
- drv.bus_perf_client = msm_bus_scale_register_client(bus_scale_data);
+ drv.bus_perf_client = msm_bus_scale_register_client(drv.bus_scale);
if (!drv.bus_perf_client) {
dev_err(drv.dev, "unable to register bus client\n");
BUG();
}
ret = msm_bus_scale_client_update_request(drv.bus_perf_client,
- drv.max_acpu_lvl->l2_level->bw_level);
+ drv.l2_freq_tbl[drv.max_acpu_lvl->l2_level].bw_level);
if (ret)
dev_err(drv.dev, "initial bandwidth req failed (%d)\n", ret);
}
@@ -792,13 +792,11 @@
tbl->vdd_core = 1150000;
}
-static void __init select_freq_plan(struct acpu_level *const *pvs_tbl,
- u32 qfprom_phys)
+static int __init select_freq_plan(u32 qfprom_phys)
{
- const struct acpu_level *l;
void __iomem *qfprom_base;
u32 pte_efuse, pvs, tbl_idx;
- char *pvs_names[] = { "Slow", "Nominal", "Fast", "Unknown" };
+ char *pvs_names[] = { "Slow", "Nominal", "Fast", "Faster", "Unknown" };
qfprom_base = ioremap(qfprom_phys, SZ_256);
/* Select frequency tables. */
@@ -820,6 +818,9 @@
case 0x3:
tbl_idx = PVS_FAST;
break;
+ case 0x4:
+ tbl_idx = PVS_FASTER;
+ break;
default:
tbl_idx = PVS_UNKNOWN;
break;
@@ -828,24 +829,29 @@
tbl_idx = PVS_UNKNOWN;
dev_err(drv.dev, "Unable to map QFPROM base\n");
}
- dev_info(drv.dev, "ACPU PVS: %s\n", pvs_names[tbl_idx]);
if (tbl_idx == PVS_UNKNOWN) {
tbl_idx = PVS_SLOW;
dev_warn(drv.dev, "ACPU PVS: Defaulting to %s\n",
pvs_names[tbl_idx]);
+ } else {
+ dev_info(drv.dev, "ACPU PVS: %s\n", pvs_names[tbl_idx]);
}
- drv.acpu_freq_tbl = pvs_tbl[tbl_idx];
- if (krait_needs_vmin())
- krait_apply_vmin(drv.acpu_freq_tbl);
+ return tbl_idx;
+}
- /* Find the max supported scaling frequency. */
- for (l = drv.acpu_freq_tbl; l->speed.khz != 0; l++)
+static const struct acpu_level __init *find_max_acpu_lvl(struct acpu_level *tbl)
+{
+ struct acpu_level *l, *max_lvl = NULL;
+
+ for (l = tbl; l->speed.khz != 0; l++)
if (l->use_for_scaling)
- drv.max_acpu_lvl = l;
- BUG_ON(!drv.max_acpu_lvl);
- dev_info(drv.dev, "Max ACPU freq: %lu KHz\n",
- drv.max_acpu_lvl->speed.khz);
+ max_lvl = l;
+
+ BUG_ON(!max_lvl);
+ dev_info(drv.dev, "Max CPU freq: %lu KHz\n", max_lvl->speed.khz);
+
+ return max_lvl;
}
static struct acpuclk_data acpuclk_krait_data = {
@@ -855,20 +861,51 @@
.wait_for_irq_khz = STBY_KHZ,
};
-int __init acpuclk_krait_init(struct device *dev,
- const struct acpuclk_krait_params *params)
+static void __init drv_data_init(struct device *dev,
+ const struct acpuclk_krait_params *params)
{
- struct scalable *l2;
+ int tbl_idx;
+
+ drv.dev = dev;
+ drv.scalable = kmemdup(params->scalable, params->scalable_size,
+ GFP_KERNEL);
+ BUG_ON(!drv.scalable);
+
+ drv.hfpll_data = kmemdup(params->hfpll_data, sizeof(*drv.hfpll_data),
+ GFP_KERNEL);
+ BUG_ON(!drv.hfpll_data);
+
+ drv.l2_freq_tbl = kmemdup(params->l2_freq_tbl, params->l2_freq_tbl_size,
+ GFP_KERNEL);
+ BUG_ON(!drv.l2_freq_tbl);
+
+ drv.bus_scale = kmemdup(params->bus_scale, sizeof(*drv.bus_scale),
+ GFP_KERNEL);
+ BUG_ON(!drv.bus_scale);
+ drv.bus_scale->usecase = kmemdup(drv.bus_scale->usecase,
+ drv.bus_scale->num_usecases * sizeof(*drv.bus_scale->usecase),
+ GFP_KERNEL);
+ BUG_ON(!drv.bus_scale->usecase);
+
+ tbl_idx = select_freq_plan(params->qfprom_phys_base);
+ drv.acpu_freq_tbl = kmemdup(params->pvs_tables[tbl_idx].table,
+ params->pvs_tables[tbl_idx].size,
+ GFP_KERNEL);
+ BUG_ON(!drv.acpu_freq_tbl);
+
+ drv.max_acpu_lvl = find_max_acpu_lvl(drv.acpu_freq_tbl);
+}
+
+static void __init hw_init(void)
+{
+ struct scalable *l2 = &drv.scalable[L2];
int cpu, rc;
- drv.scalable = params->scalable;
- drv.l2_freq_tbl = params->l2_freq_tbl;
- drv.dev = dev;
+ if (krait_needs_vmin())
+ krait_apply_vmin(drv.acpu_freq_tbl);
- select_freq_plan(params->pvs_acpu_freq_tbl, params->qfprom_phys_base);
- bus_init(params->bus_scale_data);
+ bus_init();
- l2 = &drv.scalable[L2];
l2->hfpll_base = ioremap(l2->hfpll_phys_base, SZ_32);
BUG_ON(!l2->hfpll_base);
@@ -878,17 +915,23 @@
rc = rpm_regulator_init(l2, VREG_HFPLL_B,
l2->vreg[VREG_HFPLL_B].max_vdd, false);
BUG_ON(rc);
-
- rc = init_clock_sources(l2, &drv.max_acpu_lvl->l2_level->speed);
+ rc = init_clock_sources(l2,
+ &drv.l2_freq_tbl[drv.max_acpu_lvl->l2_level].speed);
BUG_ON(rc);
for_each_online_cpu(cpu) {
rc = per_cpu_init(cpu);
BUG_ON(rc);
}
+}
+
+int __init acpuclk_krait_init(struct device *dev,
+ const struct acpuclk_krait_params *params)
+{
+ drv_data_init(dev, params);
+ hw_init();
cpufreq_table_init();
-
acpuclk_register(&acpuclk_krait_data);
register_hotcpu_notifier(&acpuclk_cpu_notifier);
diff --git a/arch/arm/mach-msm/acpuclock-krait.h b/arch/arm/mach-msm/acpuclock-krait.h
index f121548..f92aaf3 100644
--- a/arch/arm/mach-msm/acpuclock-krait.h
+++ b/arch/arm/mach-msm/acpuclock-krait.h
@@ -15,7 +15,7 @@
#define __ARCH_ARM_MACH_MSM_ACPUCLOCK_KRAIT_H
#define STBY_KHZ 1
-
+#define L2(x) (x)
#define BW_MBPS(_bw) \
{ \
.vectors = (struct msm_bus_vectors[]){ \
@@ -50,6 +50,7 @@
PVS_SLOW = 0,
PVS_NOMINAL,
PVS_FAST,
+ PVS_FASTER,
PVS_UNKNOWN,
NUM_PVS
};
@@ -146,7 +147,7 @@
struct acpu_level {
const int use_for_scaling;
const struct core_speed speed;
- const struct l2_level *l2_level;
+ const unsigned int l2_level;
int vdd_core;
};
@@ -162,7 +163,7 @@
* @droop_offset: Droop controller register offset from base address.
* @droop_val: Value to initialize the @config_offset register to.
* @low_vdd_l_max: Maximum "L" value supported at HFPLL_VDD_LOW.
- * @vdd: voltage requirements for each VDD level.
+ * @vdd: voltage requirements for each VDD level for the L2 PLL.
*/
struct hfpll_data {
const u32 mode_offset;
@@ -185,7 +186,6 @@
* @aux_clk_sel_phys: Physical address of auxiliary MUX.
* @aux_clk_sel: Auxiliary mux input to select at boot.
* @l2cpmr_iaddr: Indirect address of the CPMR MUX/divider CP15 register.
- * @hfpll_data: Descriptive data of HFPLL hardware.
* @cur_speed: Pointer to currently-set speed.
* @l2_vote: L2 performance level vote associate with the current CPU speed.
* @vreg: Array of voltage regulators needed by the scalable.
@@ -197,29 +197,42 @@
const phys_addr_t aux_clk_sel_phys;
const u32 aux_clk_sel;
const u32 l2cpmr_iaddr;
- const struct hfpll_data *hfpll_data;
const struct core_speed *cur_speed;
- const struct l2_level *l2_vote;
+ unsigned int l2_vote;
struct vreg vreg[NUM_VREG];
bool initialized;
};
/**
+ * struct pvs_table - CPU performance level table and size.
+ * @table: CPU performance level table
+ * @size: sizeof(@table)
+ */
+struct pvs_table {
+ struct acpu_level *table;
+ size_t size;
+};
+
+/**
* struct acpuclk_krait_params - SoC specific driver parameters.
* @scalable: Array of scalables.
- * @pvs_acpu_freq_tbl: Array of CPU frequency tables.
+ * @scalable_size: Size of @scalable.
+ * @hfpll_data: HFPLL configuration data.
+ * @pvs_tables: CPU frequency tables.
* @l2_freq_tbl: L2 frequency table.
- * @l2_freq_tbl_size: Number of rows in @l2_freq_tbl.
+ * @l2_freq_tbl_size: Size of @l2_freq_tbl.
* @qfprom_phys_base: Physical base address of QFPROM.
- * @bus_scale_data: MSM bus driver parameters.
+ * @bus_scale: MSM bus driver parameters.
*/
struct acpuclk_krait_params {
struct scalable *scalable;
- struct acpu_level *pvs_acpu_freq_tbl[NUM_PVS];
- const struct l2_level *l2_freq_tbl;
- const size_t l2_freq_tbl_size;
- const phys_addr_t qfprom_phys_base;
- struct msm_bus_scale_pdata *bus_scale_data;
+ size_t scalable_size;
+ struct hfpll_data *hfpll_data;
+ struct pvs_table *pvs_tables;
+ struct l2_level *l2_freq_tbl;
+ size_t l2_freq_tbl_size;
+ phys_addr_t qfprom_phys_base;
+ struct msm_bus_scale_pdata *bus_scale;
};
/**
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 29416de..a84cb39 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -179,11 +179,11 @@
};
VREG_CONSUMERS(S5) = {
REGULATOR_SUPPLY("8921_s5", NULL),
- REGULATOR_SUPPLY("krait0", NULL),
+ REGULATOR_SUPPLY("krait0", "acpuclk-8064"),
};
VREG_CONSUMERS(S6) = {
REGULATOR_SUPPLY("8921_s6", NULL),
- REGULATOR_SUPPLY("krait1", NULL),
+ REGULATOR_SUPPLY("krait1", "acpuclk-8064"),
};
VREG_CONSUMERS(S7) = {
REGULATOR_SUPPLY("8921_s7", NULL),
@@ -237,11 +237,11 @@
};
VREG_CONSUMERS(8821_S0) = {
REGULATOR_SUPPLY("8821_s0", NULL),
- REGULATOR_SUPPLY("krait2", NULL),
+ REGULATOR_SUPPLY("krait2", "acpuclk-8064"),
};
VREG_CONSUMERS(8821_S1) = {
REGULATOR_SUPPLY("8821_s1", NULL),
- REGULATOR_SUPPLY("krait3", NULL),
+ REGULATOR_SUPPLY("krait3", "acpuclk-8064"),
};
VREG_CONSUMERS(EXT_5V) = {
REGULATOR_SUPPLY("ext_5v", NULL),
@@ -606,10 +606,37 @@
int msm8064_pm8921_regulator_pdata_len __devinitdata =
ARRAY_SIZE(msm8064_pm8921_regulator_pdata);
+#define RPM_REG_MAP(_id, _sleep_also, _voter, _supply, _dev_name) \
+ { \
+ .vreg_id = RPM_VREG_ID_PM8921_##_id, \
+ .sleep_also = _sleep_also, \
+ .voter = _voter, \
+ .supply = _supply, \
+ .dev_name = _dev_name, \
+ }
+static struct rpm_regulator_consumer_mapping
+ msm_rpm_regulator_consumer_mapping[] __devinitdata = {
+ RPM_REG_MAP(LVS7, 0, 1, "krait0_hfpll", "acpuclk-8064"),
+ RPM_REG_MAP(LVS7, 0, 2, "krait1_hfpll", "acpuclk-8064"),
+ RPM_REG_MAP(LVS7, 0, 4, "krait2_hfpll", "acpuclk-8064"),
+ RPM_REG_MAP(LVS7, 0, 5, "krait3_hfpll", "acpuclk-8064"),
+ RPM_REG_MAP(LVS7, 0, 6, "l2_hfpll", "acpuclk-8064"),
+ RPM_REG_MAP(L24, 0, 1, "krait0_mem", "acpuclk-8064"),
+ RPM_REG_MAP(L24, 0, 2, "krait1_mem", "acpuclk-8064"),
+ RPM_REG_MAP(L24, 0, 4, "krait2_mem", "acpuclk-8064"),
+ RPM_REG_MAP(L24, 0, 5, "krait3_mem", "acpuclk-8064"),
+ RPM_REG_MAP(S3, 0, 1, "krait0_dig", "acpuclk-8064"),
+ RPM_REG_MAP(S3, 0, 2, "krait1_dig", "acpuclk-8064"),
+ RPM_REG_MAP(S3, 0, 4, "krait2_dig", "acpuclk-8064"),
+ RPM_REG_MAP(S3, 0, 5, "krait3_dig", "acpuclk-8064"),
+};
+
struct rpm_regulator_platform_data apq8064_rpm_regulator_pdata __devinitdata = {
.init_data = apq8064_rpm_regulator_init_data,
.num_regulators = ARRAY_SIZE(apq8064_rpm_regulator_init_data),
.version = RPM_VREG_VERSION_8960,
.vreg_id_vdd_mem = RPM_VREG_ID_PM8921_L24,
.vreg_id_vdd_dig = RPM_VREG_ID_PM8921_S3,
+ .consumer_map = msm_rpm_regulator_consumer_mapping,
+ .consumer_map_len = ARRAY_SIZE(msm_rpm_regulator_consumer_mapping),
};
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 1f59909..3e07833 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2049,12 +2049,6 @@
},
};
-static struct msm_pm_sleep_status_data msm_pm_slp_sts_data = {
- .base_addr = MSM_ACC0_BASE + 0x08,
- .cpu_offset = MSM_ACC1_BASE - MSM_ACC0_BASE,
- .mask = 1UL << 13,
-};
-
static void __init apq8064_init_buses(void)
{
msm_bus_rpm_set_mt_mask();
@@ -2160,7 +2154,7 @@
};
static struct platform_device *common_devices[] __initdata = {
- &msm8960_device_acpuclk,
+ &apq8064_device_acpuclk,
&apq8064_device_dmov,
&apq8064_device_qup_spi_gsbi5,
&apq8064_device_ext_5v_vreg,
@@ -2965,7 +2959,6 @@
msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
msm_spm_l2_init(msm_spm_l2_data);
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
- msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
apq8064_epm_adc_init();
}
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index 739dc85..292c031 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -131,6 +131,7 @@
* appropriate function.
*/
#define DISP_RST_GPIO 58
+#define DISP_3D_2D_MODE 1
static int mipi_dsi_cdp_panel_power(int on)
{
static struct regulator *reg_l8, *reg_l23, *reg_l2;
@@ -183,6 +184,19 @@
gpio_free(DISP_RST_GPIO);
return -ENODEV;
}
+ rc = gpio_request(DISP_3D_2D_MODE, "disp_3d_2d");
+ if (rc) {
+ pr_err("request gpio DISP_3D_2D_MODE failed, rc=%d\n",
+ rc);
+ gpio_free(DISP_3D_2D_MODE);
+ return -ENODEV;
+ }
+ rc = gpio_direction_output(DISP_3D_2D_MODE, 0);
+ if (rc) {
+ pr_err("gpio_direction_output failed for %d gpio rc=%d\n",
+ DISP_3D_2D_MODE, rc);
+ return -ENODEV;
+ }
dsi_power_on = true;
}
if (on) {
@@ -222,6 +236,8 @@
gpio_set_value(DISP_RST_GPIO, 0);
usleep(20);
gpio_set_value(DISP_RST_GPIO, 1);
+ gpio_set_value(DISP_3D_2D_MODE, 1);
+ usleep(20);
} else {
gpio_set_value(DISP_RST_GPIO, 0);
@@ -256,6 +272,8 @@
pr_err("set_optimum_mode l2 failed, rc=%d\n", rc);
return -EINVAL;
}
+ gpio_set_value(DISP_3D_2D_MODE, 0);
+ usleep(20);
}
return 0;
}
diff --git a/arch/arm/mach-msm/board-8930-gpu.c b/arch/arm/mach-msm/board-8930-gpu.c
index 105a5aa..bd343c1 100644
--- a/arch/arm/mach-msm/board-8930-gpu.c
+++ b/arch/arm/mach-msm/board-8930-gpu.c
@@ -162,8 +162,8 @@
{
unsigned int version = socinfo_get_version();
- if (cpu_is_msm8627())
- kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 400000000;
+ if (cpu_is_msm8930aa())
+ kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 450000000;
if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
(SOCINFO_VERSION_MINOR(version) == 2))
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 88c0924..d7a077c 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -2401,12 +2401,6 @@
.mode = MSM_PM_BOOT_CONFIG_TZ,
};
-static struct msm_pm_sleep_status_data msm_pm_slp_sts_data = {
- .base_addr = MSM_ACC0_BASE + 0x08,
- .cpu_offset = MSM_ACC1_BASE - MSM_ACC0_BASE,
- .mask = 1UL << 13,
-};
-
#ifdef CONFIG_I2C
#define I2C_SURF 1
#define I2C_FFA (1 << 1)
@@ -2603,7 +2597,6 @@
ARRAY_SIZE(msm_slim_devices));
change_memory_power = &msm8930_change_memory_power;
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
- msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
if (PLATFORM_IS_CHARM25())
platform_add_devices(mdm_devices, ARRAY_SIZE(mdm_devices));
diff --git a/arch/arm/mach-msm/board-8960-gpiomux.c b/arch/arm/mach-msm/board-8960-gpiomux.c
index 53e7c9e..5851990 100644
--- a/arch/arm/mach-msm/board-8960-gpiomux.c
+++ b/arch/arm/mach-msm/board-8960-gpiomux.c
@@ -76,6 +76,18 @@
.pull = GPIOMUX_PULL_NONE,
};
+static struct gpiomux_setting gsbi8_uartdm_active_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi8_uartdm_suspended_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
static struct gpiomux_setting gsbi9_active_cfg = {
.func = GPIOMUX_FUNC_2,
.drv = GPIOMUX_DRV_8MA,
@@ -310,6 +322,37 @@
},
};
#endif
+/* GSBI8 UART GPIOs for Atheros Bluetooth */
+static struct msm_gpiomux_config msm8960_gsbi8_uartdm_configs[] = {
+ {
+ .gpio = 34,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi8_uartdm_suspended_cfg,
+ [GPIOMUX_ACTIVE] = &gsbi8_uartdm_active_cfg,
+ }
+ },
+ {
+ .gpio = 35,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi8_uartdm_suspended_cfg,
+ [GPIOMUX_ACTIVE] = &gsbi8_uartdm_active_cfg,
+ }
+ },
+ {
+ .gpio = 36,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi8_uartdm_suspended_cfg,
+ [GPIOMUX_ACTIVE] = &gsbi8_uartdm_active_cfg,
+ }
+ },
+ {
+ .gpio = 37,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi8_uartdm_suspended_cfg,
+ [GPIOMUX_ACTIVE] = &gsbi8_uartdm_active_cfg,
+ }
+ },
+};
static struct msm_gpiomux_config msm8960_fusion_gsbi_configs[] = {
{
@@ -988,6 +1031,10 @@
msm_gpiomux_install(msm8960_mdp_vsync_configs,
ARRAY_SIZE(msm8960_mdp_vsync_configs));
+ if (socinfo_get_platform_subtype() != PLATFORM_SUBTYPE_SGLTE)
+ msm_gpiomux_install(msm8960_gsbi8_uartdm_configs,
+ ARRAY_SIZE(msm8960_gsbi8_uartdm_configs));
+
if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)
msm_gpiomux_install(msm8960_gsbi8_uart_configs,
ARRAY_SIZE(msm8960_gsbi8_uart_configs));
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index 650ac28..6ad44d8 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -181,11 +181,11 @@
};
VREG_CONSUMERS(S5) = {
REGULATOR_SUPPLY("8921_s5", NULL),
- REGULATOR_SUPPLY("krait0", NULL),
+ REGULATOR_SUPPLY("krait0", "acpuclk-8960"),
};
VREG_CONSUMERS(S6) = {
REGULATOR_SUPPLY("8921_s6", NULL),
- REGULATOR_SUPPLY("krait1", NULL),
+ REGULATOR_SUPPLY("krait1", "acpuclk-8960"),
};
VREG_CONSUMERS(S7) = {
REGULATOR_SUPPLY("8921_s7", NULL),
@@ -561,10 +561,34 @@
int msm_pm8921_regulator_pdata_len __devinitdata =
ARRAY_SIZE(msm_pm8921_regulator_pdata);
+#define RPM_REG_MAP(_id, _sleep_also, _voter, _supply, _dev_name) \
+ { \
+ .vreg_id = RPM_VREG_ID_PM8921_##_id, \
+ .sleep_also = _sleep_also, \
+ .voter = _voter, \
+ .supply = _supply, \
+ .dev_name = _dev_name, \
+ }
+static struct rpm_regulator_consumer_mapping
+ msm_rpm_regulator_consumer_mapping[] __devinitdata = {
+ RPM_REG_MAP(L23, 0, 1, "krait0_l23", "acpuclk-8960"),
+ RPM_REG_MAP(L23, 0, 2, "krait1_l23", "acpuclk-8960"),
+ RPM_REG_MAP(L23, 0, 6, "l2_l23", "acpuclk-8960"),
+ RPM_REG_MAP(L24, 0, 1, "krait0_mem", "acpuclk-8960"),
+ RPM_REG_MAP(L24, 0, 2, "krait1_mem", "acpuclk-8960"),
+ RPM_REG_MAP(S3, 0, 1, "krait0_dig", "acpuclk-8960"),
+ RPM_REG_MAP(S3, 0, 2, "krait1_dig", "acpuclk-8960"),
+ RPM_REG_MAP(S8, 0, 1, "krait0_s8", "acpuclk-8960"),
+ RPM_REG_MAP(S8, 0, 2, "krait1_s8", "acpuclk-8960"),
+ RPM_REG_MAP(S8, 0, 6, "l2_s8", "acpuclk-8960"),
+};
+
struct rpm_regulator_platform_data msm_rpm_regulator_pdata __devinitdata = {
.init_data = msm_rpm_regulator_init_data,
.num_regulators = ARRAY_SIZE(msm_rpm_regulator_init_data),
.version = RPM_VREG_VERSION_8960,
.vreg_id_vdd_mem = RPM_VREG_ID_PM8921_L24,
.vreg_id_vdd_dig = RPM_VREG_ID_PM8921_S3,
+ .consumer_map = msm_rpm_regulator_consumer_mapping,
+ .consumer_map_len = ARRAY_SIZE(msm_rpm_regulator_consumer_mapping),
};
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 0fcaf78..d56bdbd 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -2321,12 +2321,6 @@
.src_clk_rate = 24000000,
};
-static struct msm_pm_sleep_status_data msm_pm_slp_sts_data = {
- .base_addr = MSM_ACC0_BASE + 0x08,
- .cpu_offset = MSM_ACC1_BASE - MSM_ACC0_BASE,
- .mask = 1UL << 13,
-};
-
static struct ks8851_pdata spi_eth_pdata = {
.irq_gpio = KS8851_IRQ_GPIO,
.rst_gpio = KS8851_RST_GPIO,
@@ -2462,7 +2456,36 @@
static struct msm_serial_hs_platform_data msm_uart_dm9_pdata = {
.gpio_config = configure_uart_gpios,
};
+
+static int configure_gsbi8_uart_gpios(int on)
+{
+ int ret = 0, i;
+ int uart_gpios[] = {34, 35, 36, 37};
+
+ for (i = 0; i < ARRAY_SIZE(uart_gpios); i++) {
+ if (on) {
+ ret = gpio_request(uart_gpios[i], NULL);
+ if (ret) {
+ pr_err("%s: unable to request uart gpio[%d]\n",
+ __func__, uart_gpios[i]);
+ break;
+ }
+ } else {
+ gpio_free(uart_gpios[i]);
+ }
+ }
+
+ if (ret && on && i)
+ for (; i >= 0; i--)
+ gpio_free(uart_gpios[i]);
+ return ret;
+}
+
+static struct msm_serial_hs_platform_data msm_uart_dm8_pdata = {
+ .gpio_config = configure_gsbi8_uart_gpios,
+};
#else
+static struct msm_serial_hs_platform_data msm_uart_dm8_pdata;
static struct msm_serial_hs_platform_data msm_uart_dm9_pdata;
#endif
@@ -3047,7 +3070,6 @@
slim_register_board_info(msm_slim_devices,
ARRAY_SIZE(msm_slim_devices));
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
- msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
}
static void __init msm8960_rumi3_init(void)
@@ -3077,7 +3099,6 @@
slim_register_board_info(msm_slim_devices,
ARRAY_SIZE(msm_slim_devices));
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
- msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
}
static void __init msm8960_cdp_init(void)
@@ -3143,6 +3164,11 @@
platform_device_register(&msm_device_uart_dm9);
}
+ /* For 8960 Standalone External Bluetooth Interface */
+ if (socinfo_get_platform_subtype() != PLATFORM_SUBTYPE_SGLTE) {
+ msm_device_uart_dm8.dev.platform_data = &msm_uart_dm8_pdata;
+ platform_device_register(&msm_device_uart_dm8);
+ }
platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
msm8960_pm8921_gpio_mpp_init();
platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
@@ -3161,7 +3187,6 @@
msm8960_init_dsps();
change_memory_power = &msm8960_change_memory_power;
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
- msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
mdm_sglte_device.dev.platform_data = &sglte_platform_data;
platform_device_register(&mdm_sglte_device);
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 7562c83..6b46a2f 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -383,6 +383,7 @@
static void __init msm_8974_early_memory(void)
{
reserve_info = &msm_8974_reserve_info;
+ of_scan_flat_dt(dt_scan_for_memory_reserve, msm_8974_reserve_table);
}
void __init msm_8974_reserve(void)
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 7db4bda..ba4e098 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -48,7 +48,6 @@
#include <mach/msm_battery.h>
#include <linux/smsc911x.h>
#include <linux/atmel_maxtouch.h>
-#include <linux/fmem.h>
#include <linux/msm_adc.h>
#include <linux/ion.h>
#include "devices.h"
@@ -448,9 +447,6 @@
.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
.cached = 1,
.memory_type = MEMTYPE_EBI1,
- .request_region = request_fmem_c_region,
- .release_region = release_fmem_c_region,
- .reusable = 1,
};
static struct platform_device android_pmem_adsp_device = {
@@ -778,14 +774,6 @@
static void msm7x27a_cfg_uart2dm_serial(void) { }
#endif
-static struct fmem_platform_data fmem_pdata;
-
-static struct platform_device fmem_device = {
- .name = "fmem",
- .id = 1,
- .dev = { .platform_data = &fmem_pdata },
-};
-
static struct platform_device *rumi_sim_devices[] __initdata = {
&msm_device_dmov,
&msm_device_smd,
@@ -823,7 +811,6 @@
&android_pmem_device,
&android_pmem_adsp_device,
&android_pmem_audio_device,
- &fmem_device,
&msm_device_nand,
&msm_device_snd,
&msm_device_adspdec,
@@ -966,32 +953,10 @@
{
#ifdef CONFIG_ANDROID_PMEM
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
- unsigned int i;
- unsigned int reusable_count = 0;
-
android_pmem_adsp_pdata.size = pmem_adsp_size;
android_pmem_pdata.size = pmem_mdp_size;
android_pmem_audio_pdata.size = pmem_audio_size;
- fmem_pdata.size = 0;
- fmem_pdata.align = PAGE_SIZE;
-
- /* Find pmem devices that should use FMEM (reusable) memory.
- */
- for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i) {
- struct android_pmem_platform_data *pdata = pmem_pdata_array[i];
-
- if (!reusable_count && pdata->reusable)
- fmem_pdata.size += pdata->size;
-
- reusable_count += (pdata->reusable) ? 1 : 0;
-
- if (pdata->reusable && reusable_count > 1) {
- pr_err("%s: Too many PMEM devices specified as reusable. PMEM device %s was not configured as reusable.\n",
- __func__, pdata->name);
- pdata->reusable = 0;
- }
- }
#endif
#endif
}
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index bd73b70..a694557 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -31,7 +31,6 @@
#include <linux/memblock.h>
#include <linux/input/ft5x06_ts.h>
#include <linux/msm_adc.h>
-#include <linux/fmem.h>
#include <linux/regulator/msm-gpio-regulator.h>
#include <linux/ion.h>
#include <asm/mach/mmc.h>
@@ -394,9 +393,6 @@
.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
.cached = 1,
.memory_type = MEMTYPE_EBI1,
- .request_region = request_fmem_c_region,
- .release_region = release_fmem_c_region,
- .reusable = 1,
};
static struct platform_device android_pmem_adsp_device = {
@@ -639,14 +635,6 @@
},
};
-static struct fmem_platform_data fmem_pdata;
-
-static struct platform_device fmem_device = {
- .name = "fmem",
- .id = 1,
- .dev = { .platform_data = &fmem_pdata },
-};
-
#define GPIO_VREG_INIT(_id, _reg_name, _gpio_label, _gpio, _active_low) \
[GPIO_VREG_ID_##_id] = { \
.init_data = { \
@@ -717,7 +705,6 @@
&asoc_msm_dai0,
&asoc_msm_dai1,
&msm_adc_device,
- &fmem_device,
#ifdef CONFIG_ION_MSM
&ion_dev,
#endif
@@ -858,32 +845,9 @@
{
#ifdef CONFIG_ANDROID_PMEM
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
- unsigned int i;
- unsigned int reusable_count = 0;
-
android_pmem_adsp_pdata.size = pmem_adsp_size;
android_pmem_pdata.size = pmem_mdp_size;
android_pmem_audio_pdata.size = pmem_audio_size;
-
- fmem_pdata.size = 0;
- fmem_pdata.align = PAGE_SIZE;
-
- /* Find pmem devices that should use FMEM (reusable) memory.
- */
- for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i) {
- struct android_pmem_platform_data *pdata = pmem_pdata_array[i];
-
- if (!reusable_count && pdata->reusable)
- fmem_pdata.size += pdata->size;
-
- reusable_count += (pdata->reusable) ? 1 : 0;
-
- if (pdata->reusable && reusable_count > 1) {
- pr_err("%s: Too many PMEM devices specified as reusable. PMEM device %s was not configured as reusable.\n",
- __func__, pdata->name);
- pdata->reusable = 0;
- }
- }
#endif
#endif
}
diff --git a/arch/arm/mach-msm/cache_erp.c b/arch/arm/mach-msm/cache_erp.c
index c3302ec..8a73c84 100644
--- a/arch/arm/mach-msm/cache_erp.c
+++ b/arch/arm/mach-msm/cache_erp.c
@@ -253,22 +253,11 @@
int print_regs = cesr & CESR_PRINT_MASK;
int log_event = cesr & CESR_LOG_EVENT_MASK;
- void *const saw_bases[] = {
- MSM_SAW0_BASE,
- MSM_SAW1_BASE,
- MSM_SAW2_BASE,
- MSM_SAW3_BASE,
- };
-
if (print_regs) {
pr_alert("L1 / TLB Error detected on CPU %d!\n", cpu);
pr_alert("\tCESR = 0x%08x\n", cesr);
pr_alert("\tCPU speed = %lu\n", acpuclk_get_rate(cpu));
pr_alert("\tMIDR = 0x%08x\n", read_cpuid_id());
- pr_alert("\tPTE fuses = 0x%08x\n",
- readl_relaxed(MSM_QFPROM_BASE + 0xC0));
- pr_alert("\tPMIC_VREG = 0x%08x\n",
- readl_relaxed(saw_bases[cpu] + 0x14));
}
if (cesr & CESR_DCTPE) {
@@ -550,12 +539,18 @@
return 0;
}
+static struct of_device_id cache_erp_match_table[] = {
+ { .compatible = "qcom,cache_erp", },
+ {}
+};
+
static struct platform_driver msm_cache_erp_driver = {
.probe = msm_cache_erp_probe,
.remove = msm_cache_erp_remove,
.driver = {
.name = MODULE_NAME,
.owner = THIS_MODULE,
+ .of_match_table = cache_erp_match_table,
},
};
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index e87dd14..56b774d 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5508,7 +5508,10 @@
CLK_LOOKUP("core_clk", gsbi5_uart_clk.c, "msm_serial_hsl.0"),
CLK_LOOKUP("core_clk", gsbi6_uart_clk.c, "msm_serial_hs.0"),
CLK_LOOKUP("core_clk", gsbi7_uart_clk.c, ""),
+ /* used on 8960 SGLTE for console */
CLK_LOOKUP("core_clk", gsbi8_uart_clk.c, "msm_serial_hsl.1"),
+ /* used on 8960 standalone with Atheros Bluetooth */
+ CLK_LOOKUP("core_clk", gsbi8_uart_clk.c, "msm_serial_hs.2"),
CLK_LOOKUP("core_clk", gsbi9_uart_clk.c, "msm_serial_hs.1"),
CLK_LOOKUP("core_clk", gsbi10_uart_clk.c, ""),
CLK_LOOKUP("core_clk", gsbi11_uart_clk.c, ""),
@@ -5560,7 +5563,10 @@
CLK_LOOKUP("iface_clk", gsbi5_p_clk.c, "msm_serial_hsl.0"),
CLK_LOOKUP("iface_clk", gsbi6_p_clk.c, "msm_serial_hs.0"),
CLK_LOOKUP("iface_clk", gsbi7_p_clk.c, ""),
+ /* used on 8960 SGLTE for serial console */
CLK_LOOKUP("iface_clk", gsbi8_p_clk.c, "msm_serial_hsl.1"),
+ /* used on 8960 standalone with Atheros Bluetooth */
+ CLK_LOOKUP("iface_clk", gsbi8_p_clk.c, "msm_serial_hs.2"),
CLK_LOOKUP("iface_clk", gsbi9_p_clk.c, "msm_serial_hs.1"),
CLK_LOOKUP("iface_clk", gsbi10_p_clk.c, "qup_i2c.10"),
CLK_LOOKUP("iface_clk", gsbi11_p_clk.c, ""),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 48f16b0..6b58257 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -2115,6 +2115,7 @@
static struct branch_clk gcc_usb30_master_clk = {
.cbcr_reg = USB30_MASTER_CBCR,
+ .bcr_reg = USB_30_BCR,
.parent = &usb30_master_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[GCC_BASE],
@@ -2149,6 +2150,7 @@
static struct branch_clk gcc_usb_hs_system_clk = {
.cbcr_reg = USB_HS_SYSTEM_CBCR,
+ .bcr_reg = USB_HS_BCR,
.parent = &usb_hs_system_clk_src.c,
.base = &virt_bases[GCC_BASE],
.c = {
@@ -2171,6 +2173,7 @@
static struct branch_clk gcc_usb_hsic_clk = {
.cbcr_reg = USB_HSIC_CBCR,
+ .bcr_reg = USB_HS_HSIC_BCR,
.parent = &usb_hsic_clk_src.c,
.base = &virt_bases[GCC_BASE],
.c = {
@@ -3987,9 +3990,9 @@
.has_sibling = 1,
.base = &virt_bases[LPASS_BASE],
.c = {
- .dbg_name = "audio_core_lpaif_codec_spkr_clk_src",
+ .dbg_name = "audio_core_lpaif_codec_spkr_osr_clk",
.ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_codec_spkr_clk_src.c),
+ CLK_INIT(audio_core_lpaif_codec_spkr_osr_clk.c),
},
};
@@ -3998,9 +4001,9 @@
.has_sibling = 1,
.base = &virt_bases[LPASS_BASE],
.c = {
- .dbg_name = "audio_core_lpaif_codec_spkr_clk_src",
+ .dbg_name = "audio_core_lpaif_codec_spkr_ebit_clk",
.ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_codec_spkr_clk_src.c),
+ CLK_INIT(audio_core_lpaif_codec_spkr_ebit_clk.c),
},
};
@@ -4011,9 +4014,9 @@
.max_div = 15,
.base = &virt_bases[LPASS_BASE],
.c = {
- .dbg_name = "audio_core_lpaif_codec_spkr_clk_src",
+ .dbg_name = "audio_core_lpaif_codec_spkr_ibit_clk",
.ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_codec_spkr_clk_src.c),
+ CLK_INIT(audio_core_lpaif_codec_spkr_ibit_clk.c),
},
};
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 8a41a7c..aa67690 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -852,6 +852,11 @@
},
};
+struct platform_device apq8064_device_acpuclk = {
+ .name = "acpuclk-8064",
+ .id = -1,
+};
+
#define SHARED_IMEM_TZ_BASE 0x2a03f720
static struct resource tzlog_resources[] = {
{
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index d74d4aa..9a0c2d7 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -292,6 +292,52 @@
.coherent_dma_mask = DMA_BIT_MASK(32),
},
};
+
+/* GSBI 8 used into UARTDM Mode */
+static struct resource msm_uart_dm8_resources[] = {
+ {
+ .start = MSM_UART8DM_PHYS,
+ .end = MSM_UART8DM_PHYS + PAGE_SIZE - 1,
+ .name = "uartdm_resource",
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = GSBI8_UARTDM_IRQ,
+ .end = GSBI8_UARTDM_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = MSM_GSBI8_PHYS,
+ .end = MSM_GSBI8_PHYS + 4 - 1,
+ .name = "gsbi_resource",
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = DMOV_HSUART_GSBI8_TX_CHAN,
+ .end = DMOV_HSUART_GSBI8_RX_CHAN,
+ .name = "uartdm_channels",
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .start = DMOV_HSUART_GSBI8_TX_CRCI,
+ .end = DMOV_HSUART_GSBI8_RX_CRCI,
+ .name = "uartdm_crci",
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static u64 msm_uart_dm8_dma_mask = DMA_BIT_MASK(32);
+struct platform_device msm_device_uart_dm8 = {
+ .name = "msm_serial_hs",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(msm_uart_dm8_resources),
+ .resource = msm_uart_dm8_resources,
+ .dev = {
+ .dma_mask = &msm_uart_dm8_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
/*
* GSBI 9 used into UARTDM Mode
* For 8960 Fusion 2.2 Primary IPC
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 2207e3c..daf70a8 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -53,6 +53,7 @@
extern struct platform_device msm_device_uart_dm12;
extern struct platform_device *msm_device_uart_gsbi9;
extern struct platform_device msm_device_uart_dm6;
+extern struct platform_device msm_device_uart_dm8;
extern struct platform_device msm_device_uart_dm9;
extern struct platform_device msm8960_device_uart_gsbi2;
@@ -419,6 +420,7 @@
extern struct platform_device msm7x27a_device_acpuclk;
extern struct platform_device msm7x27aa_device_acpuclk;
extern struct platform_device msm7x30_device_acpuclk;
+extern struct platform_device apq8064_device_acpuclk;
extern struct platform_device msm8625_device_acpuclk;
extern struct platform_device msm8627_device_acpuclk;
extern struct platform_device msm8x50_device_acpuclk;
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h
index 381ea12..6a389de 100644
--- a/arch/arm/mach-msm/include/mach/dma.h
+++ b/arch/arm/mach-msm/include/mach/dma.h
@@ -188,6 +188,12 @@
#define DMOV_HSUART_GSBI6_RX_CHAN 8
#define DMOV_HSUART_GSBI6_RX_CRCI 11
+#define DMOV_HSUART_GSBI8_TX_CHAN 7
+#define DMOV_HSUART_GSBI8_TX_CRCI 10
+
+#define DMOV_HSUART_GSBI8_RX_CHAN 8
+#define DMOV_HSUART_GSBI8_RX_CRCI 9
+
#define DMOV_HSUART_GSBI9_TX_CHAN 4
#define DMOV_HSUART_GSBI9_TX_CRCI 13
diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h
index 2596364..bf92f7d 100644
--- a/arch/arm/mach-msm/include/mach/memory.h
+++ b/arch/arm/mach-msm/include/mach/memory.h
@@ -118,6 +118,23 @@
(virt) - MEMBANK0_PAGE_OFFSET + MEMBANK0_PHYS_OFFSET)
#endif
+/*
+ * Need a temporary unique variable that no one will ever see to
+ * hold the compat string. Line number gives this easily.
+ * Need another layer of indirection to get __LINE__ to expand
+ * properly as opposed to appending and ending up with
+ * __compat___LINE__
+ */
+#define __CONCAT(a, b) ___CONCAT(a, b)
+#define ___CONCAT(a, b) a ## b
+
+#define EXPORT_COMPAT(com) \
+static char *__CONCAT(__compat_, __LINE__) __used \
+ __attribute((__section__(".exportcompat.init"))) = com
+
+extern char *__compat_exports_start[];
+extern char *__compat_exports_end[];
+
#endif
#if defined CONFIG_ARCH_MSM_SCORPION || defined CONFIG_ARCH_MSM_KRAIT
@@ -135,4 +152,5 @@
#ifndef CONFIG_ARCH_MSM7X27
#define CONSISTENT_DMA_SIZE (SZ_1M * 14)
+
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_memory_dump.h b/arch/arm/mach-msm/include/mach/msm_memory_dump.h
new file mode 100644
index 0000000..3b8c9fd
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_memory_dump.h
@@ -0,0 +1,57 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ */
+
+#ifndef __MSM_MEMORY_DUMP_H
+#define __MSM_MEMORY_DUMP_H
+
+#include <linux/types.h>
+
+enum dump_client_type {
+ MSM_CPU_CTXT = 0,
+ MSM_CACHE,
+ MSM_OCMEM,
+ MSM_ETB,
+ MSM_ETM,
+ MSM_TMC,
+ MAX_NUM_CLIENTS,
+};
+
+struct msm_client_dump {
+ enum dump_client_type id;
+ unsigned long start_addr;
+ unsigned long end_addr;
+};
+
+struct msm_dump_table {
+ u32 version;
+ u32 num_entries;
+ struct msm_client_dump client_entries[MAX_NUM_CLIENTS];
+};
+
+struct msm_memory_dump {
+ unsigned long dump_table_phys;
+ struct msm_dump_table *dump_table_ptr;
+};
+
+#define TABLE_MAJOR(val) (val >> 20)
+#define TABLE_MINOR(val) (val & 0xFFFFF)
+#define MK_TABLE(ma, mi) ((ma << 20) | mi)
+
+#ifndef CONFIG_MSM_MEMORY_DUMP
+static inline int msm_dump_table_register(struct msm_client_dump *entry)
+{
+ return -EIO;
+}
+#else
+int msm_dump_table_register(struct msm_client_dump *client_entry);
+#endif
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_memtypes.h b/arch/arm/mach-msm/include/mach/msm_memtypes.h
index 7afb38d..5ca5861 100644
--- a/arch/arm/mach-msm/include/mach/msm_memtypes.h
+++ b/arch/arm/mach-msm/include/mach/msm_memtypes.h
@@ -66,5 +66,8 @@
extern struct reserve_info *reserve_info;
+int __init dt_scan_for_memory_reserve(unsigned long node, const char *uname,
+ int depth, void *data);
+
unsigned long __init reserve_memory_for_fmem(unsigned long, unsigned long);
#endif
diff --git a/arch/arm/mach-msm/include/mach/ocmem.h b/arch/arm/mach-msm/include/mach/ocmem.h
index 927624d..415f8ed 100644
--- a/arch/arm/mach-msm/include/mach/ocmem.h
+++ b/arch/arm/mach-msm/include/mach/ocmem.h
@@ -22,7 +22,7 @@
/* Maximum number of slots in DM */
#define OCMEM_MAX_CHUNKS 32
-#define MIN_CHUNK_SIZE (SZ_1K/8)
+#define MIN_CHUNK_SIZE 128
struct ocmem_notifier;
@@ -61,7 +61,7 @@
/* IMEM Clients */
OCMEM_LP_AUDIO,
OCMEM_SENSORS,
- OCMEM_BLAST,
+ OCMEM_OTHER_OS,
OCMEM_CLIENT_MAX,
};
@@ -108,8 +108,13 @@
int ocmem_shrink(int client_id, struct ocmem_buf *buf,
unsigned long new_size);
-int ocmem_expand(int client_id, struct ocmem_buf *buf,
- unsigned long new_size);
+/* Transfer APIs */
+int ocmem_map(int client_id, struct ocmem_buf *buffer,
+ struct ocmem_map_list *list);
+
+
+int ocmem_unmap(int client_id, struct ocmem_buf *buffer,
+ struct ocmem_map_list *list);
/* Priority Enforcement APIs */
int ocmem_evict(int client_id);
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 64c9ffe..70b5a45 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -20,12 +20,13 @@
#include "ocmem.h"
#include <mach/msm_iomap.h>
#include <asm/io.h>
+#include <linux/platform_device.h>
#define OCMEM_PHYS_BASE 0xFEC00000
#define OCMEM_PHYS_SIZE 0x180000
-#define TO_OCMEM 0x1
-#define TO_DDR 0x2
+#define TO_OCMEM 0x0
+#define TO_DDR 0x1
struct ocmem_zone;
@@ -38,7 +39,7 @@
int owner;
int active_regions;
int max_regions;
- struct list_head region_list;
+ struct list_head req_list;
unsigned long z_start;
unsigned long z_end;
unsigned long z_head;
@@ -78,12 +79,24 @@
bool interleaved;
};
+struct ocmem_eviction_data {
+ struct completion completion;
+ struct list_head victim_list;
+ struct list_head req_list;
+ struct work_struct work;
+ int prio;
+ int pending;
+ bool passive;
+};
+
struct ocmem_req {
struct rw_semaphore rw_sem;
/* Chain in sched queue */
struct list_head sched_list;
/* Chain in zone list */
struct list_head zone_list;
+ /* Chain in eviction list */
+ struct list_head eviction_list;
int owner;
int prio;
uint32_t req_id;
@@ -100,6 +113,7 @@
unsigned long req_start;
unsigned long req_end;
unsigned long req_sz;
+ struct ocmem_eviction_data *edata;
};
struct ocmem_handle {
@@ -150,13 +164,20 @@
int ocmem_notifier_init(void);
int check_notifier(int);
+const char *get_name(int);
+int check_id(int);
int dispatch_notification(int, enum ocmem_notif_type, struct ocmem_buf *);
int ocmem_sched_init(void);
+int ocmem_rdm_init(struct platform_device *);
int process_allocate(int, struct ocmem_handle *, unsigned long, unsigned long,
unsigned long, bool, bool);
int process_free(int, struct ocmem_handle *);
-int process_xfer(int, struct ocmem_handle *, struct ocmem_map_list *,
- int direction);
+int process_xfer(int, struct ocmem_handle *, struct ocmem_map_list *, int);
+int process_evict(int);
+int process_restore(int);
+int process_shrink(int, struct ocmem_handle *, unsigned long);
+int ocmem_rdm_transfer(int, struct ocmem_map_list *,
+ unsigned long, int);
unsigned long process_quota(int);
#endif
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index e65f71c..ea368ae 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -49,8 +49,8 @@
static void msm_lpm_exit_sleep(void *limits, bool from_idle,
bool notify_rpm, bool collapsed)
{
- /* TODO */
- return;
+ msm_lpmrs_exit_sleep((struct msm_rpmrs_limits *)limits,
+ from_idle, notify_rpm, collapsed);
}
void msm_lpm_show_resources(void)
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
index f57f974..e5be352 100644
--- a/arch/arm/mach-msm/lpm_resources.c
+++ b/arch/arm/mach-msm/lpm_resources.c
@@ -18,14 +18,14 @@
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/cpu.h>
-#include <mach/mpm.h>
#include <linux/notifier.h>
#include <linux/hrtimer.h>
#include <linux/tick.h>
+#include <mach/mpm.h>
+#include <mach/rpm-smd.h>
#include "spm.h"
#include "lpm_resources.h"
#include "rpm-notifier.h"
-#include <mach/rpm-smd.h>
#include "idle.h"
/*Debug Definitions*/
@@ -243,6 +243,7 @@
uint32_t key, uint8_t *value)
{
int ret = 0;
+ int msg_id;
if (!handle)
return ret;
@@ -255,10 +256,18 @@
return ret;
}
- ret = msm_rpm_send_request_noirq(handle);
- if (ret < 0) {
+ msg_id = msm_rpm_send_request_noirq(handle);
+ if (!msg_id) {
pr_err("%s: Error sending RPM request key %u, handle 0x%x\n",
__func__, key, (unsigned int)handle);
+ ret = -EIO;
+ return ret;
+ }
+
+ ret = msm_rpm_wait_for_ack(msg_id);
+ if (ret < 0) {
+ pr_err("%s: Couldn't get ACK from RPM for Msg %d Error %d",
+ __func__, msg_id, ret);
return ret;
}
if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_RPM)
@@ -666,12 +675,14 @@
return ret;
}
-void msm_lpmrs_exit_sleep(uint32_t sclk_count, struct msm_rpmrs_limits *limits,
- bool from_idle, bool notify_rpm)
+void msm_lpmrs_exit_sleep(struct msm_rpmrs_limits *limits,
+ bool from_idle, bool notify_rpm, bool collapsed)
{
/* MPM exit sleep
if (msm_lpm_use_mpm(limits))
msm_mpm_exit_sleep(from_idle);*/
+
+ msm_spm_l2_set_low_power_mode(MSM_SPM_MODE_DISABLED, notify_rpm);
}
static int msm_lpm_cpu_callback(struct notifier_block *cpu_nb,
diff --git a/arch/arm/mach-msm/lpm_resources.h b/arch/arm/mach-msm/lpm_resources.h
index 9973fbf..bc06d7b 100644
--- a/arch/arm/mach-msm/lpm_resources.h
+++ b/arch/arm/mach-msm/lpm_resources.h
@@ -83,14 +83,14 @@
/**
* msm_lpmrs_exit_sleep() - Exit sleep, reset the MPM and L2 mode.
- * @ sclk_count - Sleep Clock count.
* @ limits: pointer to resource limits of the most recent low power mode.
* @from_idle: bool to determine if this call being made as a part of
* idle power collapse.
* @notify_rpm: bool that informs if this is an RPM notified power collapse.
+ * @collapsed: bool that informs if the Krait was power collapsed.
*/
-void msm_lpmrs_exit_sleep(uint32_t sclk_count, struct msm_rpmrs_limits *limits,
- bool from_idle, bool notify_rpm);
+void msm_lpmrs_exit_sleep(struct msm_rpmrs_limits *limits,
+ bool from_idle, bool notify_rpm, bool collapsed);
/**
* msm_lpmrs_module_init() - Init function that parses the device tree to
* get the low power resource attributes and registers with RPM driver for
@@ -112,9 +112,8 @@
return 0;
}
-static inline void msm_lpmrs_exit_sleep(uint32_t sclk_count,
- struct msm_rpmrs_limits *limits, bool from_idle,
- bool notify_rpm)
+static inline void msm_lpmrs_exit_sleep(struct msm_rpmrs_limits *limits,
+ bool from_idle, bool notify_rpm, bool collapsed)
{
return;
}
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index a1b21c5..63c2d3a 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -37,6 +37,7 @@
#include <mach/msm_iomap.h>
#include <mach/socinfo.h>
#include <linux/sched.h>
+#include <linux/of_fdt.h>
/* fixme */
#include <asm/tlbflush.h>
@@ -381,3 +382,117 @@
{
return fmem_set_state(FMEM_T_STATE);
}
+
+static char * const memtype_names[] = {
+ [MEMTYPE_SMI_KERNEL] = "SMI_KERNEL",
+ [MEMTYPE_SMI] = "SMI",
+ [MEMTYPE_EBI0] = "EBI0",
+ [MEMTYPE_EBI1] = "EBI1",
+};
+
+static int reserve_memory_type(char *mem_name,
+ struct memtype_reserve *reserve_table,
+ int size)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(memtype_names); i++) {
+ if (memtype_names[i] && strcmp(mem_name,
+ memtype_names[i]) == 0) {
+ reserve_table[i].size += size;
+ return 0;
+ }
+ }
+
+ pr_err("Could not find memory type %s\n", mem_name);
+ return -EINVAL;
+}
+
+static int check_for_compat(unsigned long node)
+{
+ char **start = __compat_exports_start;
+
+ for ( ; start < __compat_exports_end; start++)
+ if (of_flat_dt_is_compatible(node, *start))
+ return 1;
+
+ return 0;
+}
+
+int __init dt_scan_for_memory_reserve(unsigned long node, const char *uname,
+ int depth, void *data)
+{
+ char *memory_name_prop;
+ unsigned int *memory_remove_prop;
+ unsigned long memory_name_prop_length;
+ unsigned long memory_remove_prop_length;
+ unsigned long memory_size_prop_length;
+ unsigned int *memory_size_prop;
+ unsigned int memory_size;
+ unsigned int memory_start;
+ int ret;
+
+ memory_name_prop = of_get_flat_dt_prop(node,
+ "qcom,memory-reservation-type",
+ &memory_name_prop_length);
+ memory_remove_prop = of_get_flat_dt_prop(node,
+ "qcom,memblock-remove",
+ &memory_remove_prop_length);
+
+ if (memory_name_prop || memory_remove_prop) {
+ if (!check_for_compat(node))
+ goto out;
+ } else {
+ goto out;
+ }
+
+ if (memory_name_prop) {
+ if (strnlen(memory_name_prop, memory_name_prop_length) == 0) {
+ WARN(1, "Memory name was malformed\n");
+ goto mem_remove;
+ }
+
+ memory_size_prop = of_get_flat_dt_prop(node,
+ "qcom,memory-reservation-size",
+ &memory_size_prop_length);
+
+ if (memory_size_prop &&
+ (memory_size_prop_length == sizeof(unsigned int))) {
+ memory_size = be32_to_cpu(*memory_size_prop);
+
+ if (reserve_memory_type(memory_name_prop,
+ data, memory_size) == 0)
+ pr_info("%s reserved %s size %x\n",
+ uname, memory_name_prop, memory_size);
+ else
+ WARN(1, "Node %s reserve failed\n",
+ uname);
+ } else {
+ WARN(1, "Node %s specified bad/nonexistent size\n",
+ uname);
+ }
+ }
+
+mem_remove:
+
+ if (memory_remove_prop) {
+ if (memory_remove_prop_length != (2*sizeof(unsigned int))) {
+ WARN(1, "Memory remove malformed\n");
+ goto out;
+ }
+
+ memory_start = be32_to_cpu(memory_remove_prop[0]);
+ memory_size = be32_to_cpu(memory_remove_prop[1]);
+
+ ret = memblock_remove(memory_start, memory_size);
+ if (ret)
+ WARN(1, "Failed to remove memory %x-%x\n",
+ memory_start, memory_start+memory_size);
+ else
+ pr_info("Node %s removed memory %x-%x\n", uname,
+ memory_start, memory_start+memory_size);
+ }
+
+out:
+ return 0;
+}
diff --git a/arch/arm/mach-msm/mpm-8625.c b/arch/arm/mach-msm/mpm-8625.c
index 954e5cc..3c219be 100644
--- a/arch/arm/mach-msm/mpm-8625.c
+++ b/arch/arm/mach-msm/mpm-8625.c
@@ -221,7 +221,7 @@
/* save the contents of GIC CPU interface and Distributor
* Disable all the Interrupts, if we enter from idle pc
*/
- msm_gic_save(modem_wake, from_idle);
+ msm_gic_save();
irq_set_irq_type(MSM8625_INT_A9_M2A_6, IRQF_TRIGGER_RISING);
enable_irq(MSM8625_INT_A9_M2A_6);
pr_debug("%s going for sleep now\n", __func__);
diff --git a/arch/arm/mach-msm/msm-krait-l2-accessors.c b/arch/arm/mach-msm/msm-krait-l2-accessors.c
index 3d341e3..41a2490 100644
--- a/arch/arm/mach-msm/msm-krait-l2-accessors.c
+++ b/arch/arm/mach-msm/msm-krait-l2-accessors.c
@@ -14,19 +14,83 @@
#include <linux/spinlock.h>
#include <linux/module.h>
#include <asm/mach-types.h>
+#include <asm/cputype.h>
DEFINE_RAW_SPINLOCK(l2_access_lock);
+#define L2CPMR 0x500
+#define L2CPUCPMR 0x501
+#define L2CPUVRF8 0x708
+#define CPUNDX_MASK (0x7 << 12)
+
+/*
+ * For Krait versions found in APQ8064v1.x, save L2CPUVRF8 before
+ * L2CPMR or L2CPUCPMR writes and restore it after to work around an
+ * issue where L2CPUVRF8 becomes corrupt.
+ */
+static bool l2cpuvrf8_needs_fix(u32 reg_addr)
+{
+ switch (read_cpuid_id()) {
+ case 0x510F06F0: /* KR28M4A10 */
+ case 0x510F06F1: /* KR28M4A10B */
+ case 0x510F06F2: /* KR28M4A11 */
+ break;
+ default:
+ return false;
+ };
+
+ switch (reg_addr & ~CPUNDX_MASK) {
+ case L2CPMR:
+ case L2CPUCPMR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static u32 l2cpuvrf8_fix_save(u32 reg_addr, u32 *l2cpuvrf8_val)
+{
+ u32 l2cpuvrf8_addr = L2CPUVRF8 | (reg_addr & CPUNDX_MASK);
+
+ mb();
+ asm volatile ("mcr p15, 3, %[l2cpselr], c15, c0, 6\n\t"
+ "isb\n\t"
+ "mrc p15, 3, %[l2cpdr], c15, c0, 7\n\t"
+ : [l2cpdr]"=r" (*l2cpuvrf8_val)
+ : [l2cpselr]"r" (l2cpuvrf8_addr)
+ );
+
+ return l2cpuvrf8_addr;
+}
+
+static void l2cpuvrf8_fix_restore(u32 l2cpuvrf8_addr, u32 l2cpuvrf8_val)
+{
+ mb();
+ asm volatile ("mcr p15, 3, %[l2cpselr], c15, c0, 6\n\t"
+ "isb\n\t"
+ "mcr p15, 3, %[l2cpdr], c15, c0, 7\n\t"
+ "isb\n\t"
+ :
+ : [l2cpselr]"r" (l2cpuvrf8_addr),
+ [l2cpdr]"r" (l2cpuvrf8_val)
+ );
+}
+
u32 set_get_l2_indirect_reg(u32 reg_addr, u32 val)
{
unsigned long flags;
+ u32 uninitialized_var(l2cpuvrf8_val), l2cpuvrf8_addr = 0;
u32 ret_val;
+
/* CP15 registers are not emulated on RUMI3. */
if (machine_is_msm8960_rumi3())
return 0;
raw_spin_lock_irqsave(&l2_access_lock, flags);
+ if (l2cpuvrf8_needs_fix(reg_addr))
+ l2cpuvrf8_addr = l2cpuvrf8_fix_save(reg_addr, &l2cpuvrf8_val);
+
mb();
asm volatile ("mcr p15, 3, %[l2cpselr], c15, c0, 6\n\t"
"isb\n\t"
@@ -36,6 +100,10 @@
: [l2cpdr_read]"=r" (ret_val)
: [l2cpselr]"r" (reg_addr), [l2cpdr]"r" (val)
);
+
+ if (l2cpuvrf8_addr)
+ l2cpuvrf8_fix_restore(l2cpuvrf8_addr, l2cpuvrf8_val);
+
raw_spin_unlock_irqrestore(&l2_access_lock, flags);
return ret_val;
@@ -45,11 +113,17 @@
void set_l2_indirect_reg(u32 reg_addr, u32 val)
{
unsigned long flags;
+ u32 uninitialized_var(l2cpuvrf8_val), l2cpuvrf8_addr = 0;
+
/* CP15 registers are not emulated on RUMI3. */
if (machine_is_msm8960_rumi3())
return;
raw_spin_lock_irqsave(&l2_access_lock, flags);
+
+ if (l2cpuvrf8_needs_fix(reg_addr))
+ l2cpuvrf8_addr = l2cpuvrf8_fix_save(reg_addr, &l2cpuvrf8_val);
+
mb();
asm volatile ("mcr p15, 3, %[l2cpselr], c15, c0, 6\n\t"
"isb\n\t"
@@ -58,6 +132,10 @@
:
: [l2cpselr]"r" (reg_addr), [l2cpdr]"r" (val)
);
+
+ if (l2cpuvrf8_addr)
+ l2cpuvrf8_fix_restore(l2cpuvrf8_addr, l2cpuvrf8_val);
+
raw_spin_unlock_irqrestore(&l2_access_lock, flags);
}
EXPORT_SYMBOL(set_l2_indirect_reg);
diff --git a/arch/arm/mach-msm/msm_memory_dump.c b/arch/arm/mach-msm/msm_memory_dump.c
new file mode 100644
index 0000000..4f48a0d
--- /dev/null
+++ b/arch/arm/mach-msm/msm_memory_dump.c
@@ -0,0 +1,78 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 <asm/cacheflush.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/notifier.h>
+#include <linux/export.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_memory_dump.h>
+
+
+/*TODO: Needs to be set to correct value */
+#define DUMP_TABLE_OFFSET 0x20
+#define MSM_DUMP_TABLE_VERSION MK_TABLE(1, 0)
+
+static struct msm_memory_dump mem_dump_data;
+
+static int msm_memory_dump_panic(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ writel_relaxed(0, MSM_IMEM_BASE + DUMP_TABLE_OFFSET);
+ return 0;
+}
+
+static struct notifier_block msm_memory_dump_blk = {
+ .notifier_call = msm_memory_dump_panic,
+};
+
+int msm_dump_table_register(struct msm_client_dump *client_entry)
+{
+ struct msm_client_dump *entry;
+ struct msm_dump_table *table = mem_dump_data.dump_table_ptr;
+
+ if (!table || table->num_entries >= MAX_NUM_CLIENTS)
+ return -EINVAL;
+ entry = &table->client_entries[table->num_entries];
+ entry->id = client_entry->id;
+ entry->start_addr = client_entry->start_addr;
+ entry->end_addr = client_entry->end_addr;
+ table->num_entries++;
+ /* flush cache */
+ dmac_flush_range(table, table + sizeof(struct msm_dump_table));
+ return 0;
+}
+EXPORT_SYMBOL(msm_dump_table_register);
+
+static int __init init_memory_dump(void)
+{
+ struct msm_dump_table *table;
+
+ mem_dump_data.dump_table_ptr = kzalloc(sizeof(struct msm_dump_table),
+ GFP_KERNEL);
+ if (!mem_dump_data.dump_table_ptr) {
+ printk(KERN_ERR "unable to allocate memory for dump table\n");
+ return -ENOMEM;
+ }
+ table = mem_dump_data.dump_table_ptr;
+ table->version = MSM_DUMP_TABLE_VERSION;
+ mem_dump_data.dump_table_phys = virt_to_phys(table);
+ /* TODO: Need to write physical address of table to IMEM */
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &msm_memory_dump_blk);
+ printk(KERN_INFO "MSM Memory Dump table set up\n");
+ return 0;
+}
+
+early_initcall(init_memory_dump);
+
diff --git a/arch/arm/mach-msm/msm_smem_iface.c b/arch/arm/mach-msm/msm_smem_iface.c
new file mode 100644
index 0000000..b09fda5
--- /dev/null
+++ b/arch/arm/mach-msm/msm_smem_iface.c
@@ -0,0 +1,44 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 "msm_smem_iface.h"
+
+/**
+ * mem_get_cpr_info() - Copy Core Power Reduction (CPR) driver specific
+ * data from Shared memory (SMEM).
+ * @cpr_info - Pointer to CPR data. Memory to be allocated and freed by
+ * calling function.
+ *
+ * Copy CPR specific data from SMEM to cpr_info.
+ */
+
+void msm_smem_get_cpr_info(struct cpr_info_type *cpr_info)
+{
+ struct boot_info_for_apps *boot_info;
+ struct cpr_info_type *temp_cpr_info;
+ uint32_t smem_boot_info_size;
+
+ boot_info = smem_get_entry(SMEM_BOOT_INFO_FOR_APPS,
+ &smem_boot_info_size);
+ BUG_ON(!boot_info);
+ if (smem_boot_info_size < sizeof(struct boot_info_for_apps)) {
+ pr_err("%s: Shared boot info data structure too small!\n",
+ __func__);
+ BUG();
+ } else {
+ pr_debug("%s: Shared boot info available.\n", __func__);
+ }
+ temp_cpr_info = (struct cpr_info_type *) &(boot_info->cpr_info);
+ cpr_info->ring_osc = temp_cpr_info->ring_osc;
+ cpr_info->turbo_quot = temp_cpr_info->turbo_quot;
+ cpr_info->pvs_fuse = temp_cpr_info->pvs_fuse;
+}
diff --git a/arch/arm/mach-msm/msm_smem_iface.h b/arch/arm/mach-msm/msm_smem_iface.h
new file mode 100644
index 0000000..2da0232
--- /dev/null
+++ b/arch/arm/mach-msm/msm_smem_iface.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_SMEM_IFACE_H
+#define __ARCH_ARM_MACH_MSM_SMEM_IFACE_H
+
+#include <mach/msm_smsm.h>
+#include "smd_private.h"
+
+#define MAX_KEY_EVENTS 10
+#define MAX_SEC_KEY_PAYLOAD 32
+
+struct boot_shared_ssd_status_info {
+ uint32_t update_status; /* To check if process is successful or not */
+ uint32_t bl_error_code; /* To indicate error code in bootloader */
+};
+
+struct boot_symmetric_key_info {
+ uint32_t key_len; /* Encrypted Symmetric Key Length */
+ uint32_t iv_len; /* Initialization Vector Length */
+ uint8_t key[MAX_SEC_KEY_PAYLOAD]; /* Encrypted Symmetric Key */
+ uint8_t iv[MAX_SEC_KEY_PAYLOAD]; /* Initialization Vector */
+};
+
+struct cpr_info_type {
+ uint8_t ring_osc; /* CPR FUSE [0]: TURBO RO SEL BIT */
+ uint8_t turbo_quot; /* CPRFUSE[1:7] : TURBO QUOT*/
+ uint8_t pvs_fuse; /* TURBO PVS FUSE */
+};
+
+struct boot_info_for_apps {
+ uint32_t apps_image_start_addr; /* apps image start address */
+ uint32_t boot_flags; /* bit mask of upto 32 flags */
+ struct boot_shared_ssd_status_info ssd_status_info; /* SSD status */
+ struct boot_symmetric_key_info key_info;
+ uint16_t boot_keys_pressed[MAX_KEY_EVENTS]; /* Log of key presses */
+ uint32_t timetick; /* Modem tick timer value before apps out of reset */
+ struct cpr_info_type cpr_info;
+ uint8_t PAD[25];
+};
+
+void msm_smem_get_cpr_info(struct cpr_info_type *cpr_info);
+
+#endif /* __ARCH_ARM_MACH_MSM_SMEM_IFACE_H */
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
index a233080..753f6fb 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -30,8 +30,9 @@
*/
#define OCMEM_REGION_CTL_BASE 0xFDD0003C
-#define OCMEM_REGION_CTL_SIZE 0xC
+#define OCMEM_REGION_CTL_SIZE 0xFD0
#define REGION_ENABLE 0x00003333
+#define GRAPHICS_REGION_CTL (0x17F000)
struct ocmem_partition {
const char *name;
@@ -55,6 +56,7 @@
static struct ocmem_plat_data *ocmem_pdata;
#define CLIENT_NAME_MAX 10
+
/* Must be in sync with enum ocmem_client */
static const char *client_names[OCMEM_CLIENT_MAX] = {
"graphics",
@@ -64,7 +66,7 @@
"voice",
"lp_audio",
"sensors",
- "blast",
+ "other_os",
};
struct ocmem_quota_table {
@@ -85,7 +87,7 @@
{ "voice", OCMEM_VOICE, 0x0, 0x0, 0x0, 0 },
{ "hp_audio", OCMEM_HP_AUDIO, 0x0, 0x0, 0x0, 0},
{ "lp_audio", OCMEM_LP_AUDIO, 0x80000, 0xA0000, 0xA0000, 0},
- { "blast", OCMEM_BLAST, 0x120000, 0x20000, 0x20000, 0},
+ { "other_os", OCMEM_OTHER_OS, 0x120000, 0x20000, 0x20000, 0},
{ "sensors", OCMEM_SENSORS, 0x140000, 0x40000, 0x40000, 0},
};
@@ -99,6 +101,18 @@
return -EINVAL;
}
+int check_id(int id)
+{
+ return (id < OCMEM_CLIENT_MAX && id >= OCMEM_GRAPHICS);
+}
+
+const char *get_name(int id)
+{
+ if (!check_id(id))
+ return NULL;
+ return client_names[id];
+}
+
inline unsigned long phys_to_offset(unsigned long addr)
{
if (!ocmem_pdata)
@@ -455,7 +469,7 @@
zone->owner = part->id;
zone->active_regions = 0;
zone->max_regions = 0;
- INIT_LIST_HEAD(&zone->region_list);
+ INIT_LIST_HEAD(&zone->req_list);
zone->z_ops = z_ops;
if (part->p_tail) {
z_ops->allocate = allocate_tail;
@@ -519,6 +533,13 @@
writel_relaxed(REGION_ENABLE, ocmem_region_vbase);
writel_relaxed(REGION_ENABLE, ocmem_region_vbase + 4);
writel_relaxed(REGION_ENABLE, ocmem_region_vbase + 8);
+ /* Enable the ocmem graphics mpU as a workaround in Virtio */
+ /* This will be programmed by TZ after TZ support is integrated */
+ writel_relaxed(GRAPHICS_REGION_CTL, ocmem_region_vbase + 0xFCC);
+
+ if (ocmem_rdm_init(pdev))
+ return -EBUSY;
+
dev_dbg(dev, "initialized successfully\n");
return 0;
}
diff --git a/arch/arm/mach-msm/ocmem_api.c b/arch/arm/mach-msm/ocmem_api.c
index bed13de..bb32fca 100644
--- a/arch/arm/mach-msm/ocmem_api.c
+++ b/arch/arm/mach-msm/ocmem_api.c
@@ -13,10 +13,8 @@
#include <linux/slab.h>
#include <mach/ocmem_priv.h>
-static inline int check_id(int id)
-{
- return (id < OCMEM_CLIENT_MAX && id >= OCMEM_GRAPHICS);
-}
+static DEFINE_MUTEX(ocmem_eviction_lock);
+static DECLARE_BITMAP(evicted, OCMEM_CLIENT_MAX);
static struct ocmem_handle *generate_handle(void)
{
@@ -61,6 +59,24 @@
return 0;
}
+static int __ocmem_shrink(int id, struct ocmem_buf *buf, unsigned long len)
+{
+ int ret = 0;
+ struct ocmem_handle *handle = buffer_to_handle(buf);
+
+ if (!handle)
+ return -EINVAL;
+
+ mutex_lock(&handle->handle_mutex);
+ ret = process_shrink(id, handle, len);
+ mutex_unlock(&handle->handle_mutex);
+
+ if (ret)
+ return -EINVAL;
+
+ return 0;
+}
+
static struct ocmem_buf *__ocmem_allocate_range(int id, unsigned long min,
unsigned long max, unsigned long step, bool block, bool wait)
{
@@ -218,6 +234,15 @@
return __ocmem_free(client_id, buffer);
}
+int ocmem_shrink(int client_id, struct ocmem_buf *buffer, unsigned long len)
+{
+ if (!buffer)
+ return -EINVAL;
+ if (len >= buffer->len)
+ return -EINVAL;
+ return __ocmem_shrink(client_id, buffer, len);
+}
+
int pre_validate_chunk_list(struct ocmem_map_list *list)
{
int i = 0;
@@ -236,8 +261,12 @@
for (i = 0; i < list->num_chunks; i++) {
if (!chunks[i].ddr_paddr ||
- chunks[i].size < MIN_CHUNK_SIZE)
+ chunks[i].size < MIN_CHUNK_SIZE ||
+ !IS_ALIGNED(chunks[i].size, MIN_CHUNK_SIZE)) {
+ pr_err("Invalid ocmem chunk at index %d (p: %lx, size %lx)\n",
+ i, chunks[i].ddr_paddr, chunks[i].size);
return -EINVAL;
+ }
}
return 0;
}
@@ -265,7 +294,7 @@
return -EINVAL;
}
- if (!pre_validate_chunk_list(list))
+ if (pre_validate_chunk_list(list) != 0)
return -EINVAL;
handle = buffer_to_handle(buffer);
@@ -303,14 +332,10 @@
return -EINVAL;
}
- if (!pre_validate_chunk_list(list))
+ if (pre_validate_chunk_list(list) != 0)
return -EINVAL;
handle = buffer_to_handle(buffer);
-
- if (!handle)
- return -EINVAL;
-
mutex_lock(&handle->handle_mutex);
ret = process_xfer(client_id, handle, list, TO_DDR);
mutex_unlock(&handle->handle_mutex);
@@ -325,3 +350,52 @@
}
return process_quota(client_id);
}
+
+/* Synchronous eviction/restore calls */
+/* Only a single eviction or restoration is allowed */
+/* Evictions/Restorations cannot be concurrent with other maps */
+int ocmem_evict(int client_id)
+{
+ int ret = 0;
+
+ if (!check_id(client_id)) {
+ pr_err("ocmem: Invalid client id: %d\n", client_id);
+ return -EINVAL;
+ }
+
+ mutex_lock(&ocmem_eviction_lock);
+ if (test_bit(client_id, evicted)) {
+ pr_err("ocmem: Previous eviction was not restored by %d\n",
+ client_id);
+ mutex_unlock(&ocmem_eviction_lock);
+ return -EINVAL;
+ }
+
+ ret = process_evict(client_id);
+ if (ret == 0)
+ set_bit(client_id, evicted);
+
+ mutex_unlock(&ocmem_eviction_lock);
+ return ret;
+}
+
+int ocmem_restore(int client_id)
+{
+ int ret = 0;
+
+ if (!check_id(client_id)) {
+ pr_err("ocmem: Invalid client id: %d\n", client_id);
+ return -EINVAL;
+ }
+
+ mutex_lock(&ocmem_eviction_lock);
+ if (!test_bit(client_id, evicted)) {
+ pr_err("ocmem: No previous eviction by %d\n", client_id);
+ mutex_unlock(&ocmem_eviction_lock);
+ return -EINVAL;
+ }
+ ret = process_restore(client_id);
+ clear_bit(client_id, evicted);
+ mutex_unlock(&ocmem_eviction_lock);
+ return ret;
+}
diff --git a/arch/arm/mach-msm/ocmem_notifier.c b/arch/arm/mach-msm/ocmem_notifier.c
index 4754f44..9fbcd73 100644
--- a/arch/arm/mach-msm/ocmem_notifier.c
+++ b/arch/arm/mach-msm/ocmem_notifier.c
@@ -24,11 +24,6 @@
unsigned listeners;
} notifiers[OCMEM_CLIENT_MAX];
-static int check_id(int id)
-{
- return (id < OCMEM_CLIENT_MAX && id >= OCMEM_GRAPHICS);
-}
-
int check_notifier(int id)
{
int ret = 0;
diff --git a/arch/arm/mach-msm/ocmem_rdm.c b/arch/arm/mach-msm/ocmem_rdm.c
new file mode 100644
index 0000000..6b93d04
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem_rdm.c
@@ -0,0 +1,238 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/rbtree.h>
+#include <linux/genalloc.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <mach/ocmem_priv.h>
+
+#define RDM_MAX_ENTRIES 32
+#define RDM_MAX_CLIENTS 2
+
+/* Data Mover Parameters */
+#define DM_BLOCK_128 0x0
+#define DM_BLOCK_256 0x1
+#define DM_BR_ID_LPASS 0x0
+#define DM_BR_ID_GPS 0x1
+
+#define DM_INTR_CLR (0x8)
+#define DM_INTR_MASK (0xC)
+#define DM_GEN_STATUS (0x10)
+#define DM_STATUS (0x14)
+#define DM_CTRL (0x1000)
+#define DM_TBL_BASE (0x1010)
+#define DM_TBL_IDX(x) ((x) * 0x18)
+#define DM_TBL_n(x) (DM_TBL_BASE + (DM_TBL_IDX(x)))
+#define DM_TBL_n_offset(x) DM_TBL_n(x)
+#define DM_TBL_n_size(x) (DM_TBL_n(x)+0x4)
+#define DM_TBL_n_paddr(x) (DM_TBL_n(x)+0x8)
+#define DM_TBL_n_ctrl(x) (DM_TBL_n(x)+0x10)
+
+#define BR_CTRL (0x0)
+#define BR_CLIENT_BASE (0x4)
+#define BR_CLIENT_n_IDX(x) ((x) * 0x4)
+#define BR_CLIENT_n_ctrl(x) (BR_CLIENT_BASE + (BR_CLIENT_n_IDX(x)))
+#define BR_STATUS (0x14)
+/* 16 entries per client are supported */
+/* Use entries 0 - 15 for client0 */
+#define BR_CLIENT0_MASK (0x1000)
+/* Use entries 16- 31 for client1 */
+#define BR_CLIENT1_MASK (0x2010)
+
+#define BR_TBL_BASE (0x40)
+#define BR_TBL_IDX(x) ((x) * 0x18)
+#define BR_TBL_n(x) (BR_TBL_BASE + (BR_TBL_IDX(x)))
+#define BR_TBL_n_offset(x) BR_TBL_n(x)
+#define BR_TBL_n_size(x) (BR_TBL_n(x)+0x4)
+#define BR_TBL_n_paddr(x) (BR_TBL_n(x)+0x8)
+#define BR_TBL_n_ctrl(x) (BR_TBL_n(x)+0x10)
+
+/* Constants and Shifts */
+#define BR_TBL_ENTRY_ENABLE 0x1
+#define BR_TBL_START 0x0
+#define BR_TBL_END 0x8
+#define BR_RW_SHIFT 0x2
+
+#define DM_TBL_START 0x10
+#define DM_TBL_END 0x18
+#define DM_CLIENT_SHIFT 0x8
+#define DM_BR_ID_SHIFT 0x4
+#define DM_BR_BLK_SHIFT 0x1
+#define DM_DIR_SHIFT 0x0
+
+#define DM_DONE 0x1
+#define DM_INTR_ENABLE 0x0
+#define DM_INTR_DISABLE 0x1
+
+static void *br_base;
+static void *dm_base;
+
+static atomic_t dm_pending;
+static wait_queue_head_t dm_wq;
+/* Shadow tables for debug purposes */
+struct ocmem_br_table {
+ unsigned int offset;
+ unsigned int size;
+ unsigned int ddr_low;
+ unsigned int ddr_high;
+ unsigned int ctrl;
+} br_table[RDM_MAX_ENTRIES];
+
+/* DM Table replicates an entire BR table */
+/* Note: There are more than 1 BRs in the system */
+struct ocmem_dm_table {
+ unsigned int offset;
+ unsigned int size;
+ unsigned int ddr_low;
+ unsigned int ddr_high;
+ unsigned int ctrl;
+} dm_table[RDM_MAX_ENTRIES];
+
+/* Wrapper that will shadow these values later */
+static int ocmem_read(void *at)
+{
+ return readl_relaxed(at);
+}
+
+/* Wrapper that will shadow these values later */
+static int ocmem_write(unsigned long val, void *at)
+{
+ writel_relaxed(val, at);
+ return 0;
+}
+
+static inline int client_ctrl_id(int id)
+{
+ return (id == OCMEM_SENSORS) ? 1 : 0;
+}
+
+static inline int client_slot_start(int id)
+{
+
+ return client_ctrl_id(id) * 16;
+}
+
+static irqreturn_t ocmem_dm_irq_handler(int irq, void *dev_id)
+{
+ atomic_set(&dm_pending, 0);
+ ocmem_write(DM_INTR_DISABLE, dm_base + DM_INTR_CLR);
+ wake_up_interruptible(&dm_wq);
+ return IRQ_HANDLED;
+}
+
+/* Lock during transfers */
+int ocmem_rdm_transfer(int id, struct ocmem_map_list *clist,
+ unsigned long start, int direction)
+{
+ int num_chunks = clist->num_chunks;
+ int slot = client_slot_start(id);
+ int table_start = 0;
+ int table_end = 0;
+ int br_ctrl = 0;
+ int br_id = 0;
+ int dm_ctrl = 0;
+ int i = 0;
+ int j = 0;
+ int status = 0;
+
+ for (i = 0, j = slot; i < num_chunks; i++, j++) {
+
+ struct ocmem_chunk *chunk = &clist->chunks[i];
+ int sz = chunk->size;
+ int paddr = chunk->ddr_paddr;
+ int tbl_n_ctrl = 0;
+
+ tbl_n_ctrl |= BR_TBL_ENTRY_ENABLE;
+ if (chunk->ro)
+ tbl_n_ctrl |= (1 << BR_RW_SHIFT);
+
+ /* Table Entry n of BR and DM */
+ ocmem_write(start, br_base + BR_TBL_n_offset(j));
+ ocmem_write(sz, br_base + BR_TBL_n_size(j));
+ ocmem_write(paddr, br_base + BR_TBL_n_paddr(j));
+ ocmem_write(tbl_n_ctrl, br_base + BR_TBL_n_ctrl(j));
+
+ ocmem_write(start, dm_base + DM_TBL_n_offset(j));
+ ocmem_write(sz, dm_base + DM_TBL_n_size(j));
+ ocmem_write(paddr, dm_base + DM_TBL_n_paddr(j));
+ ocmem_write(tbl_n_ctrl, dm_base + DM_TBL_n_ctrl(j));
+
+ start += sz;
+ }
+
+ br_id = client_ctrl_id(id);
+ table_start = slot;
+ table_end = slot + num_chunks - 1;
+ br_ctrl |= (table_start << BR_TBL_START);
+ br_ctrl |= (table_end << BR_TBL_END);
+
+ ocmem_write(br_ctrl, (br_base + BR_CLIENT_n_ctrl(br_id)));
+ /* Enable BR */
+ ocmem_write(0x1, br_base + BR_CTRL);
+
+ /* Compute DM Control Value */
+ dm_ctrl |= (table_start << DM_TBL_START);
+ dm_ctrl |= (table_end << DM_TBL_END);
+
+ dm_ctrl |= (DM_BR_ID_LPASS << DM_BR_ID_SHIFT);
+ dm_ctrl |= (DM_BLOCK_256 << DM_BR_BLK_SHIFT);
+ dm_ctrl |= (direction << DM_DIR_SHIFT);
+
+ status = ocmem_read(dm_base + DM_STATUS);
+ pr_debug("Transfer status before %x\n", status);
+ atomic_set(&dm_pending, 1);
+ /* Trigger DM */
+ ocmem_write(dm_ctrl, dm_base + DM_CTRL);
+ pr_debug("ocmem: rdm: dm_ctrl %x br_ctrl %x\n", dm_ctrl, br_ctrl);
+
+ wait_event_interruptible(dm_wq,
+ atomic_read(&dm_pending) == 0);
+
+ return 0;
+}
+
+int ocmem_rdm_init(struct platform_device *pdev)
+{
+
+ struct ocmem_plat_data *pdata = NULL;
+ int rc = 0;
+
+ pdata = platform_get_drvdata(pdev);
+
+ br_base = pdata->br_base;
+ dm_base = pdata->dm_base;
+
+ rc = devm_request_irq(&pdev->dev, pdata->dm_irq, ocmem_dm_irq_handler,
+ IRQF_TRIGGER_RISING, "ocmem_dm_irq", pdata);
+
+ if (rc) {
+ dev_err(&pdev->dev, "Failed to request dm irq");
+ return -EINVAL;
+ }
+
+ init_waitqueue_head(&dm_wq);
+ /* enable dm interrupts */
+ ocmem_write(DM_INTR_ENABLE, dm_base + DM_INTR_MASK);
+ return 0;
+}
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index 10a267c..f6d066d 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -54,7 +54,7 @@
MIN_PRIO = 0x0,
NO_PRIO = MIN_PRIO,
PRIO_SENSORS = 0x1,
- PRIO_BLAST = 0x1,
+ PRIO_OTHER_OS = 0x1,
PRIO_LP_AUDIO = 0x1,
PRIO_HP_AUDIO = 0x2,
PRIO_VOICE = 0x3,
@@ -75,6 +75,21 @@
*/
#define SCHED_DELAY 10
+static struct list_head rdm_queue;
+static struct mutex rdm_mutex;
+static struct workqueue_struct *ocmem_rdm_wq;
+static struct workqueue_struct *ocmem_eviction_wq;
+
+static struct ocmem_eviction_data *evictions[OCMEM_CLIENT_MAX];
+
+struct ocmem_rdm_work {
+ int id;
+ struct ocmem_map_list *list;
+ struct ocmem_handle *handle;
+ int direction;
+ struct work_struct work;
+};
+
/* OCMEM Operational modes */
enum ocmem_client_modes {
OCMEM_PERFORMANCE = 1,
@@ -107,7 +122,7 @@
{OCMEM_VOICE, PRIO_VOICE, OCMEM_PASSIVE, OCMEM_BLOCKED},
{OCMEM_LP_AUDIO, PRIO_LP_AUDIO, OCMEM_LOW_POWER, OCMEM_SYSNOC},
{OCMEM_SENSORS, PRIO_SENSORS, OCMEM_LOW_POWER, OCMEM_SYSNOC},
- {OCMEM_BLAST, PRIO_BLAST, OCMEM_LOW_POWER, OCMEM_SYSNOC},
+ {OCMEM_OTHER_OS, PRIO_OTHER_OS, OCMEM_LOW_POWER, OCMEM_SYSNOC},
};
static struct rb_root sched_tree;
@@ -119,6 +134,8 @@
struct rb_node region_rb;
/* Hash map of requests */
struct idr region_idr;
+ /* Chain in eviction list */
+ struct list_head eviction_list;
unsigned long r_start;
unsigned long r_end;
unsigned long r_sz;
@@ -244,6 +261,7 @@
if (!p)
return NULL;
idr_init(&p->region_idr);
+ INIT_LIST_HEAD(&p->eviction_list);
p->r_start = p->r_end = p->r_sz = 0x0;
p->max_prio = NO_PRIO;
return p;
@@ -461,10 +479,14 @@
{
int rc = 0;
+ down_write(&req->rw_sem);
+
mutex_lock(&sched_mutex);
rc = __sched_map(req);
mutex_unlock(&sched_mutex);
+ up_write(&req->rw_sem);
+
if (rc == OP_FAIL)
return -EINVAL;
@@ -475,10 +497,14 @@
{
int rc = 0;
+ down_write(&req->rw_sem);
+
mutex_lock(&sched_mutex);
rc = __sched_unmap(req);
mutex_unlock(&sched_mutex);
+ up_write(&req->rw_sem);
+
if (rc == OP_FAIL)
return -EINVAL;
@@ -713,6 +739,104 @@
}
/* Must be called with sched_mutex held */
+static int __sched_shrink(struct ocmem_req *req, unsigned long new_sz)
+{
+ int owner = req->owner;
+ int ret = 0;
+
+ struct ocmem_req *matched_req = NULL;
+ struct ocmem_region *matched_region = NULL;
+ struct ocmem_region *region = NULL;
+ unsigned long alloc_addr = 0x0;
+
+ struct ocmem_zone *zone = get_zone(owner);
+
+ BUG_ON(!zone);
+
+ /* The shrink should not be called for zero size */
+ BUG_ON(new_sz == 0);
+
+ matched_region = find_region_match(req->req_start, req->req_end);
+ matched_req = find_req_match(req->req_id, matched_region);
+
+ if (!matched_region || !matched_req)
+ goto invalid_op_error;
+ if (matched_req != req)
+ goto invalid_op_error;
+
+
+ ret = zone->z_ops->free(zone,
+ matched_req->req_start, matched_req->req_sz);
+
+ if (ret < 0) {
+ pr_err("Zone Allocation operation failed\n");
+ goto internal_error;
+ }
+
+ alloc_addr = zone->z_ops->allocate(zone, new_sz);
+
+ if (alloc_addr < 0) {
+ pr_err("Zone Allocation operation failed\n");
+ goto internal_error;
+ }
+
+ /* Detach the region from the interval tree */
+ /* This is to guarantee that the change in size
+ * causes the tree to be rebalanced if required */
+
+ detach_req(matched_region, req);
+ if (req_count(matched_region) == 0) {
+ remove_region(matched_region);
+ region = matched_region;
+ } else {
+ region = create_region();
+ if (!region) {
+ pr_err("ocmem: Unable to create region\n");
+ goto internal_error;
+ }
+ }
+ /* update the request */
+ req->req_start = alloc_addr;
+ req->req_sz = new_sz;
+ req->req_end = alloc_addr + req->req_sz;
+
+ if (req_count(region) == 0) {
+ remove_region(matched_region);
+ destroy_region(matched_region);
+ }
+
+ /* update request state */
+ SET_STATE(req, R_MUST_GROW);
+ SET_STATE(req, R_MUST_MAP);
+ req->op = SCHED_MAP;
+
+ /* attach the request to the region */
+ attach_req(region, req);
+ populate_region(region, req);
+ update_region_prio(region);
+
+ /* update the tree with new region */
+ if (insert_region(region)) {
+ pr_err("ocmem: Failed to insert the region\n");
+ zone->z_ops->free(zone, alloc_addr, new_sz);
+ detach_req(region, req);
+ update_region_prio(region);
+ /* req will be destroyed by the caller */
+ goto region_error;
+ }
+ return OP_COMPLETE;
+
+region_error:
+ destroy_region(region);
+internal_error:
+ pr_err("ocmem: shrink: Failed\n");
+ return OP_FAIL;
+invalid_op_error:
+ pr_err("ocmem: shrink: Failed to find matching region\n");
+ return OP_FAIL;
+}
+
+/* Must be called with sched_mutex held */
static int __sched_allocate(struct ocmem_req *req, bool can_block,
bool can_wait)
{
@@ -906,12 +1030,6 @@
return req;
}
-int process_xfer(int id, struct ocmem_handle *handle,
- struct ocmem_map_list *list, int direction)
-{
-
- return 0;
-}
unsigned long process_quota(int id)
{
@@ -989,6 +1107,35 @@
return 0;
}
+static int do_shrink(struct ocmem_req *req, unsigned long shrink_size)
+{
+
+ int rc = 0;
+ struct ocmem_buf *buffer = NULL;
+
+ down_write(&req->rw_sem);
+ buffer = req->buffer;
+
+ /* Take the scheduler mutex */
+ mutex_lock(&sched_mutex);
+ rc = __sched_shrink(req, shrink_size);
+ mutex_unlock(&sched_mutex);
+
+ if (rc == OP_FAIL)
+ goto err_op_fail;
+
+ else if (rc == OP_COMPLETE) {
+ buffer->addr = device_address(req->owner, req->req_start);
+ buffer->len = req->req_sz;
+ }
+
+ up_write(&req->rw_sem);
+ return 0;
+err_op_fail:
+ up_write(&req->rw_sem);
+ return -EINVAL;
+}
+
static void ocmem_sched_wk_func(struct work_struct *work);
DECLARE_DELAYED_WORK(ocmem_sched_thread, ocmem_sched_wk_func);
@@ -1076,6 +1223,250 @@
return 0;
}
+static void ocmem_rdm_worker(struct work_struct *work)
+{
+ int offset = 0;
+ int rc = 0;
+ int event;
+ struct ocmem_rdm_work *work_data = container_of(work,
+ struct ocmem_rdm_work, work);
+ int id = work_data->id;
+ struct ocmem_map_list *list = work_data->list;
+ int direction = work_data->direction;
+ struct ocmem_handle *handle = work_data->handle;
+ struct ocmem_req *req = handle_to_req(handle);
+ struct ocmem_buf *buffer = handle_to_buffer(handle);
+
+ down_write(&req->rw_sem);
+ offset = phys_to_offset(req->req_start);
+ rc = ocmem_rdm_transfer(id, list, offset, direction);
+ if (work_data->direction == TO_OCMEM)
+ event = (rc == 0) ? OCMEM_MAP_DONE : OCMEM_MAP_FAIL;
+ else
+ event = (rc == 0) ? OCMEM_UNMAP_DONE : OCMEM_UNMAP_FAIL;
+
+ up_write(&req->rw_sem);
+ kfree(work_data);
+ dispatch_notification(id, event, buffer);
+}
+
+int queue_transfer(struct ocmem_req *req, struct ocmem_handle *handle,
+ struct ocmem_map_list *list, int direction)
+{
+ struct ocmem_rdm_work *work_data = NULL;
+
+ down_write(&req->rw_sem);
+
+ work_data = kzalloc(sizeof(struct ocmem_rdm_work), GFP_ATOMIC);
+ if (!work_data)
+ BUG();
+
+ work_data->handle = handle;
+ work_data->list = list;
+ work_data->id = req->owner;
+ work_data->direction = direction;
+ INIT_WORK(&work_data->work, ocmem_rdm_worker);
+ up_write(&req->rw_sem);
+ queue_work(ocmem_rdm_wq, &work_data->work);
+ return 0;
+}
+
+int process_xfer_out(int id, struct ocmem_handle *handle,
+ struct ocmem_map_list *list)
+{
+ struct ocmem_req *req = NULL;
+ int rc = 0;
+
+ req = handle_to_req(handle);
+
+ if (!req)
+ return -EINVAL;
+
+ if (!is_mapped(req)) {
+ pr_err("Buffer is not already mapped\n");
+ goto transfer_out_error;
+ }
+
+ rc = process_unmap(req, req->req_start, req->req_end);
+ if (rc < 0) {
+ pr_err("Unmapping the buffer failed\n");
+ goto transfer_out_error;
+ }
+
+ rc = queue_transfer(req, handle, list, TO_DDR);
+
+ if (rc < 0) {
+ pr_err("Failed to queue rdm transfer to DDR\n");
+ goto transfer_out_error;
+ }
+
+ return 0;
+
+transfer_out_error:
+ return -EINVAL;
+}
+
+int process_xfer_in(int id, struct ocmem_handle *handle,
+ struct ocmem_map_list *list)
+{
+ struct ocmem_req *req = NULL;
+ int rc = 0;
+
+ req = handle_to_req(handle);
+
+ if (!req)
+ return -EINVAL;
+
+ if (is_mapped(req)) {
+ pr_err("Buffer is already mapped\n");
+ goto transfer_in_error;
+ }
+
+ rc = process_map(req, req->req_start, req->req_end);
+ if (rc < 0) {
+ pr_err("Mapping the buffer failed\n");
+ goto transfer_in_error;
+ }
+
+ rc = queue_transfer(req, handle, list, TO_OCMEM);
+
+ if (rc < 0) {
+ pr_err("Failed to queue rdm transfer to OCMEM\n");
+ goto transfer_in_error;
+ }
+
+ return 0;
+transfer_in_error:
+ return -EINVAL;
+}
+
+int process_shrink(int id, struct ocmem_handle *handle, unsigned long size)
+{
+ struct ocmem_req *req = NULL;
+ struct ocmem_buf *buffer = NULL;
+ struct ocmem_eviction_data *edata = NULL;
+ int rc = 0;
+
+ if (is_blocked(id)) {
+ pr_err("Client %d cannot request free\n", id);
+ return -EINVAL;
+ }
+
+ req = handle_to_req(handle);
+ buffer = handle_to_buffer(handle);
+
+ if (!req)
+ return -EINVAL;
+
+ if (req->req_start != core_address(id, buffer->addr)) {
+ pr_err("Invalid buffer handle passed for shrink\n");
+ return -EINVAL;
+ }
+
+ edata = req->edata;
+
+ if (is_tcm(req->owner))
+ do_unmap(req);
+
+ if (size == 0) {
+ pr_info("req %p being shrunk to zero\n", req);
+ rc = do_free(req);
+ if (rc < 0)
+ return -EINVAL;
+ } else {
+ rc = do_shrink(req, size);
+ if (rc < 0)
+ return -EINVAL;
+ }
+
+ edata->pending--;
+ if (edata->pending == 0) {
+ pr_debug("All regions evicted");
+ complete(&edata->completion);
+ }
+
+ return 0;
+}
+
+int process_xfer(int id, struct ocmem_handle *handle,
+ struct ocmem_map_list *list, int direction)
+{
+ int rc = 0;
+
+ if (is_tcm(id)) {
+ WARN(1, "Mapping operation is invalid for client\n");
+ return -EINVAL;
+ }
+
+ if (direction == TO_DDR)
+ rc = process_xfer_out(id, handle, list);
+ else if (direction == TO_OCMEM)
+ rc = process_xfer_in(id, handle, list);
+ return rc;
+}
+
+int ocmem_eviction_thread(struct work_struct *work)
+{
+ return 0;
+}
+
+int process_evict(int id)
+{
+ struct ocmem_eviction_data *edata = NULL;
+ int prio = ocmem_client_table[id].priority;
+ struct rb_node *rb_node = NULL;
+ struct ocmem_req *req = NULL;
+ struct ocmem_buf buffer;
+ int j = 0;
+
+ edata = kzalloc(sizeof(struct ocmem_eviction_data), GFP_ATOMIC);
+
+ INIT_LIST_HEAD(&edata->victim_list);
+ INIT_LIST_HEAD(&edata->req_list);
+ edata->prio = prio;
+ edata->pending = 0;
+ edata->passive = 1;
+ evictions[id] = edata;
+
+ mutex_lock(&sched_mutex);
+
+ for (rb_node = rb_first(&sched_tree); rb_node;
+ rb_node = rb_next(rb_node)) {
+ struct ocmem_region *tmp_region = NULL;
+ tmp_region = rb_entry(rb_node, struct ocmem_region, region_rb);
+ if (tmp_region->max_prio < prio) {
+ for (j = id - 1; j > NO_PRIO; j--) {
+ req = find_req_match(j, tmp_region);
+ if (req) {
+ pr_info("adding %p to eviction list\n",
+ tmp_region);
+ list_add_tail(
+ &tmp_region->eviction_list,
+ &edata->victim_list);
+ list_add_tail(
+ &req->eviction_list,
+ &edata->req_list);
+ edata->pending++;
+ req->edata = edata;
+ buffer.addr = req->req_start;
+ buffer.len = 0x0;
+ dispatch_notification(req->owner,
+ OCMEM_ALLOC_SHRINK, &buffer);
+ }
+ }
+ } else {
+ pr_info("skipping %p from eviction\n", tmp_region);
+ }
+ }
+ mutex_unlock(&sched_mutex);
+ pr_debug("Waiting for all regions to be shrunk\n");
+ if (edata->pending > 0) {
+ init_completion(&edata->completion);
+ wait_for_completion(&edata->completion);
+ }
+ return 0;
+}
+
static int do_allocate(struct ocmem_req *req, bool can_block, bool can_wait)
{
int rc = 0;
@@ -1113,6 +1504,31 @@
return -EINVAL;
}
+int process_restore(int id)
+{
+ struct ocmem_req *req = NULL;
+ struct ocmem_req *next = NULL;
+ struct ocmem_eviction_data *edata = evictions[id];
+
+ if (!edata)
+ return 0;
+
+ list_for_each_entry_safe(req, next, &edata->req_list, eviction_list)
+ {
+ if (req) {
+ pr_debug("ocmem: Fetched evicted request %p\n",
+ req);
+ list_del(&req->sched_list);
+ req->op = SCHED_ALLOCATE;
+ sched_enqueue(req);
+ }
+ }
+ kfree(edata);
+ evictions[id] = NULL;
+ pr_debug("Restore all evicted regions\n");
+ ocmem_schedule_pending();
+ return 0;
+}
int process_allocate(int id, struct ocmem_handle *handle,
unsigned long min, unsigned long max,
@@ -1185,6 +1601,7 @@
rc = do_allocate(req, true, false);
+
if (rc < 0)
goto do_allocate_error;
@@ -1251,5 +1668,13 @@
for (i = MIN_PRIO; i < MAX_OCMEM_PRIO; i++)
INIT_LIST_HEAD(&sched_queue[i]);
+ mutex_init(&rdm_mutex);
+ INIT_LIST_HEAD(&rdm_queue);
+ ocmem_rdm_wq = alloc_workqueue("ocmem_rdm_wq", 0, 0);
+ if (!ocmem_rdm_wq)
+ return -ENOMEM;
+ ocmem_eviction_wq = alloc_workqueue("ocmem_eviction_wq", 0, 0);
+ if (!ocmem_eviction_wq)
+ return -ENOMEM;
return 0;
}
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 42616c6..e203667 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -24,7 +24,6 @@
#include <linux/smp.h>
#include <linux/suspend.h>
#include <linux/tick.h>
-#include <linux/delay.h>
#include <mach/msm_iomap.h>
#include <mach/socinfo.h>
#include <mach/system.h>
@@ -799,28 +798,6 @@
return 0;
}
-static struct msm_pm_sleep_status_data *msm_pm_slp_sts;
-
-static DEFINE_PER_CPU_SHARED_ALIGNED(enum msm_pm_sleep_mode,
- msm_pm_last_slp_mode);
-
-bool msm_pm_verify_cpu_pc(unsigned int cpu)
-{
- enum msm_pm_sleep_mode mode = per_cpu(msm_pm_last_slp_mode, cpu);
-
- if (msm_pm_slp_sts) {
- int acc_sts = __raw_readl(msm_pm_slp_sts->base_addr
- + cpu * msm_pm_slp_sts->cpu_offset);
-
- if ((acc_sts & msm_pm_slp_sts->mask) &&
- ((mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) ||
- (mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)))
- return true;
- }
-
- return false;
-}
-
void msm_pm_cpu_enter_lowpower(unsigned int cpu)
{
int i;
@@ -836,54 +813,14 @@
if (MSM_PM_DEBUG_HOTPLUG & msm_pm_debug_mask)
pr_notice("CPU%u: %s: shutting down cpu\n", cpu, __func__);
- if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE]) {
- per_cpu(msm_pm_last_slp_mode, cpu)
- = MSM_PM_SLEEP_MODE_POWER_COLLAPSE;
+ if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE])
msm_pm_power_collapse(false);
- } else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
- per_cpu(msm_pm_last_slp_mode, cpu)
- = MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE;
+ else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE])
msm_pm_power_collapse_standalone(false);
- } else if (allow[MSM_PM_SLEEP_MODE_RETENTION]) {
- per_cpu(msm_pm_last_slp_mode, cpu)
- = MSM_PM_SLEEP_MODE_RETENTION;
+ else if (allow[MSM_PM_SLEEP_MODE_RETENTION])
msm_pm_retention();
- } else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
- per_cpu(msm_pm_last_slp_mode, cpu)
- = MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT;
+ else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT])
msm_pm_swfi();
- } else
- per_cpu(msm_pm_last_slp_mode, cpu) = MSM_PM_SLEEP_MODE_NR;
-}
-
-int msm_pm_wait_cpu_shutdown(unsigned int cpu)
-{
-
- int timeout = 10;
-
- if (!msm_pm_slp_sts)
- return 0;
-
- while (timeout--) {
-
- /*
- * Check for the SPM of the core being hotplugged to set
- * its sleep state.The SPM sleep state indicates that the
- * core has been power collapsed.
- */
-
- int acc_sts = __raw_readl(msm_pm_slp_sts->base_addr
- + cpu * msm_pm_slp_sts->cpu_offset);
- mb();
-
- if (acc_sts & msm_pm_slp_sts->mask)
- return 0;
-
- usleep(100);
- }
- pr_warn("%s(): Timed out waiting for CPU %u SPM to enter sleep state",
- __func__, cpu);
- return -EBUSY;
}
static int msm_pm_enter(suspend_state_t state)
@@ -980,12 +917,6 @@
/******************************************************************************
* Initialization routine
*****************************************************************************/
-void __init msm_pm_init_sleep_status_data(
- struct msm_pm_sleep_status_data *data)
-{
- msm_pm_slp_sts = data;
-}
-
void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops)
{
if (ops)
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 70d54da..c722ff6 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -70,12 +70,6 @@
extern struct msm_pm_platform_data msm_pm_sleep_modes[];
-struct msm_pm_sleep_status_data {
- void *base_addr;
- uint32_t cpu_offset;
- uint32_t mask;
-};
-
struct msm_pm_sleep_ops {
void *(*lowest_limits)(bool from_idle,
enum msm_pm_sleep_mode sleep_mode, uint32_t latency_us,
@@ -93,19 +87,11 @@
int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode);
void msm_pm_cpu_enter_lowpower(unsigned int cpu);
-void __init msm_pm_init_sleep_status_data(
- struct msm_pm_sleep_status_data *sleep_data);
-
-
#ifdef CONFIG_MSM_PM8X60
void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
-int msm_pm_wait_cpu_shutdown(unsigned int cpu);
-bool msm_pm_verify_cpu_pc(unsigned int cpu);
void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops);
#else
static inline void msm_pm_set_rpm_wakeup_irq(unsigned int irq) {}
-static inline int msm_pm_wait_cpu_shutdown(unsigned int cpu) { return 0; }
-static inline bool msm_pm_verify_cpu_pc(unsigned int cpu) { return true; }
static inline void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops) {}
#endif
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/arm/mach-msm/qdsp6v2/apr.c b/arch/arm/mach-msm/qdsp6v2/apr.c
index 2403c02..a0bfb27 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr.c
@@ -372,10 +372,14 @@
if (q6.state == APR_Q6_NOIMG) {
q6.pil = pil_get("q6");
if (IS_ERR(q6.pil)) {
- rc = PTR_ERR(q6.pil);
- pr_err("APR: Unable to load q6 image, error:%d\n", rc);
- mutex_unlock(&q6.lock);
- return svc;
+ q6.pil = pil_get("adsp");
+ if (IS_ERR(q6.pil)) {
+ rc = PTR_ERR(q6.pil);
+ pr_err("APR: Unable to load q6 image, error:%d\n",
+ rc);
+ mutex_unlock(&q6.lock);
+ return svc;
+ }
}
q6.state = APR_Q6_LOADED;
}
diff --git a/arch/arm/mach-msm/rpm_log.c b/arch/arm/mach-msm/rpm_log.c
index 3ed55da..4835cef 100644
--- a/arch/arm/mach-msm/rpm_log.c
+++ b/arch/arm/mach-msm/rpm_log.c
@@ -115,13 +115,11 @@
continue;
}
/*
- * Ensure that the reported buffer size is within limits of
- * known maximum size and that all indices are 4 byte aligned.
- * These conditions are required to interact with a ULog buffer
+ * Ensure that all indices are 4 byte aligned.
+ * This conditions is required to interact with a ULog buffer
* properly.
*/
- if (tail_idx - head_idx > pdata->log_len ||
- !IS_ALIGNED((tail_idx | head_idx | *read_idx), 4))
+ if (!IS_ALIGNED((tail_idx | head_idx | *read_idx), 4))
break;
msg_len = msm_rpm_log_read(pdata, MSM_RPM_LOG_PAGE_BUFFER,
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 54512ab..948dbbb 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -559,7 +559,11 @@
* on DEM-based targets. Grabbing a wakelock in this case will
* abort the power-down sequencing.
*/
- smsm_cb_snapshot(0);
+ if (smsm_info.intr_mask &&
+ (__raw_readl(SMSM_INTR_MASK_ADDR(smsm_entry, SMSM_APPS))
+ & notify_mask)) {
+ smsm_cb_snapshot(0);
+ }
}
void smd_diag(void)
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 32f61f5..b6fb52a 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -32,6 +32,7 @@
#include <asm/sizes.h>
#include <asm/tlb.h>
#include <asm/fixmap.h>
+#include <asm/cputype.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -40,6 +41,8 @@
static unsigned long phys_initrd_start __initdata = 0;
static unsigned long phys_initrd_size __initdata = 0;
+int msm_krait_need_wfe_fixup;
+EXPORT_SYMBOL(msm_krait_need_wfe_fixup);
static int __init early_initrd(char *p)
{
@@ -916,3 +919,17 @@
__setup("keepinitrd", keepinitrd_setup);
#endif
+
+#ifdef CONFIG_MSM_KRAIT_WFE_FIXUP
+static int __init msm_krait_wfe_init(void)
+{
+ unsigned int val, midr;
+ midr = read_cpuid_id() & 0xffffff00;
+ if ((midr == 0x511f0400) || (midr == 0x510f0600)) {
+ asm volatile("mrc p15, 7, %0, c15, c0, 5" : "=r" (val));
+ msm_krait_need_wfe_fixup = (val & 0x10000) ? 1 : 0;
+ }
+ return 0;
+}
+pure_initcall(msm_krait_wfe_init);
+#endif
diff --git a/drivers/input/misc/lis3dh_acc.c b/drivers/input/misc/lis3dh_acc.c
new file mode 100644
index 0000000..af96d3f
--- /dev/null
+++ b/drivers/input/misc/lis3dh_acc.c
@@ -0,0 +1,1589 @@
+/******************** (C) COPYRIGHT 2010 STMicroelectronics ********************
+ *
+ * File Name : lis3dh_acc.c
+ * Authors : MSH - Motion Mems BU - Application Team
+ * : Matteo Dameno (matteo.dameno@st.com)
+ * : Carmine Iascone (carmine.iascone@st.com)
+ * : Samuel Huo (samuel.huo@st.com)
+ * Version : V.1.1.0
+ * Date : 07/10/2012
+ * Description : LIS3DH accelerometer sensor driver
+ *
+ *******************************************************************************
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
+ * OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE
+ * PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT.
+ * AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
+ * CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
+ * INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+ *
+ * THIS SOFTWARE IS SPECIFICALLY DESIGNED FOR EXCLUSIVE USE WITH ST PARTS.
+ *
+ ******************************************************************************
+ Revision 1.0.0 05/11/09
+ First Release;
+ Revision 1.0.3 22/01/2010
+ Linux K&R Compliant Release;
+ Revision 1.0.5 16/08/2010
+ modified _get_acceleration_data function;
+ modified _update_odr function;
+ manages 2 interrupts;
+ Revision 1.0.6 15/11/2010
+ supports sysfs;
+ no more support for ioctl;
+ Revision 1.0.7 26/11/2010
+ checks for availability of interrupts pins
+ correction on FUZZ and FLAT values;
+ Revision 1.0.8 2010/Apr/01
+ corrects a bug in interrupt pin management in 1.0.7
+ Revision 1.0.9 07/25/2011
+ Romove several unused functions,add 5ms delay in init,change sysfs attributes.
+ Revision 1.1.0 07/10/2012
+ To replace some deprecated functions for 3.4 kernel;
+ To pass the checkpatch's formatting requirement;
+ To add regulator request;
+
+ ******************************************************************************/
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/uaccess.h>
+#include <linux/workqueue.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/input/lis3dh.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+
+
+#define DEBUG 1
+
+#define G_MAX 16000
+
+
+#define SENSITIVITY_2G 1 /** mg/LSB */
+#define SENSITIVITY_4G 2 /** mg/LSB */
+#define SENSITIVITY_8G 4 /** mg/LSB */
+#define SENSITIVITY_16G 12 /** mg/LSB */
+
+
+
+
+/* Accelerometer Sensor Operating Mode */
+#define LIS3DH_ACC_ENABLE 0x01
+#define LIS3DH_ACC_DISABLE 0x00
+
+#define HIGH_RESOLUTION 0x08
+
+#define AXISDATA_REG 0x28
+#define WHOAMI_LIS3DH_ACC 0x33 /* Expected content for WAI */
+
+/* CONTROL REGISTERS */
+#define WHO_AM_I 0x0F /* WhoAmI register */
+#define TEMP_CFG_REG 0x1F /* temper sens control reg */
+/* ctrl 1: ODR3 ODR2 ODR ODR0 LPen Zenable Yenable Zenable */
+#define CTRL_REG1 0x20 /* control reg 1 */
+#define CTRL_REG2 0x21 /* control reg 2 */
+#define CTRL_REG3 0x22 /* control reg 3 */
+#define CTRL_REG4 0x23 /* control reg 4 */
+#define CTRL_REG5 0x24 /* control reg 5 */
+#define CTRL_REG6 0x25 /* control reg 6 */
+
+#define FIFO_CTRL_REG 0x2E /* FiFo control reg */
+
+#define INT_CFG1 0x30 /* interrupt 1 config */
+#define INT_SRC1 0x31 /* interrupt 1 source */
+#define INT_THS1 0x32 /* interrupt 1 threshold */
+#define INT_DUR1 0x33 /* interrupt 1 duration */
+
+
+#define TT_CFG 0x38 /* tap config */
+#define TT_SRC 0x39 /* tap source */
+#define TT_THS 0x3A /* tap threshold */
+#define TT_LIM 0x3B /* tap time limit */
+#define TT_TLAT 0x3C /* tap time latency */
+#define TT_TW 0x3D /* tap time window */
+/* end CONTROL REGISTRES */
+
+
+#define ENABLE_HIGH_RESOLUTION 1
+
+#define LIS3DH_ACC_PM_OFF 0x00
+#define LIS3DH_ACC_ENABLE_ALL_AXES 0x07
+
+
+#define PMODE_MASK 0x08
+#define ODR_MASK 0XF0
+
+#define ODR1 0x10 /* 1Hz output data rate */
+#define ODR10 0x20 /* 10Hz output data rate */
+#define ODR25 0x30 /* 25Hz output data rate */
+#define ODR50 0x40 /* 50Hz output data rate */
+#define ODR100 0x50 /* 100Hz output data rate */
+#define ODR200 0x60 /* 200Hz output data rate */
+#define ODR400 0x70 /* 400Hz output data rate */
+#define ODR1250 0x90 /* 1250Hz output data rate */
+
+
+
+#define IA 0x40
+#define ZH 0x20
+#define ZL 0x10
+#define YH 0x08
+#define YL 0x04
+#define XH 0x02
+#define XL 0x01
+/* */
+/* CTRL REG BITS*/
+#define CTRL_REG3_I1_AOI1 0x40
+#define CTRL_REG6_I2_TAPEN 0x80
+#define CTRL_REG6_HLACTIVE 0x02
+/* */
+#define NO_MASK 0xFF
+#define INT1_DURATION_MASK 0x7F
+#define INT1_THRESHOLD_MASK 0x7F
+#define TAP_CFG_MASK 0x3F
+#define TAP_THS_MASK 0x7F
+#define TAP_TLIM_MASK 0x7F
+#define TAP_TLAT_MASK NO_MASK
+#define TAP_TW_MASK NO_MASK
+
+
+/* TAP_SOURCE_REG BIT */
+#define DTAP 0x20
+#define STAP 0x10
+#define SIGNTAP 0x08
+#define ZTAP 0x04
+#define YTAP 0x02
+#define XTAZ 0x01
+
+
+#define FUZZ 0
+#define FLAT 0
+#define I2C_RETRY_DELAY 5
+#define I2C_RETRIES 5
+#define I2C_AUTO_INCREMENT 0x80
+
+/* RESUME STATE INDICES */
+#define RES_CTRL_REG1 0
+#define RES_CTRL_REG2 1
+#define RES_CTRL_REG3 2
+#define RES_CTRL_REG4 3
+#define RES_CTRL_REG5 4
+#define RES_CTRL_REG6 5
+
+#define RES_INT_CFG1 6
+#define RES_INT_THS1 7
+#define RES_INT_DUR1 8
+
+#define RES_TT_CFG 9
+#define RES_TT_THS 10
+#define RES_TT_LIM 11
+#define RES_TT_TLAT 12
+#define RES_TT_TW 13
+
+#define RES_TEMP_CFG_REG 14
+#define RES_REFERENCE_REG 15
+#define RES_FIFO_CTRL_REG 16
+
+#define RESUME_ENTRIES 17
+/* end RESUME STATE INDICES */
+
+
+struct {
+ unsigned int cutoff_ms;
+ unsigned int mask;
+} lis3dh_acc_odr_table[] = {
+ { 1, ODR1250 },
+ { 3, ODR400 },
+ { 5, ODR200 },
+ { 10, ODR100 },
+ { 20, ODR50 },
+ { 40, ODR25 },
+ { 100, ODR10 },
+ { 1000, ODR1 },
+};
+
+struct lis3dh_acc_data {
+ struct i2c_client *client;
+ struct lis3dh_acc_platform_data *pdata;
+
+ struct mutex lock;
+ struct delayed_work input_work;
+
+ struct input_dev *input_dev;
+
+ int hw_initialized;
+ /* hw_working=-1 means not tested yet */
+ int hw_working;
+ atomic_t enabled;
+ int on_before_suspend;
+
+ u8 sensitivity;
+
+ u8 resume_state[RESUME_ENTRIES];
+
+ int irq1;
+ struct work_struct irq1_work;
+ struct workqueue_struct *irq1_work_queue;
+ int irq2;
+ struct work_struct irq2_work;
+ struct workqueue_struct *irq2_work_queue;
+
+#ifdef DEBUG
+ u8 reg_addr;
+#endif
+};
+
+struct sensor_regulator {
+ struct regulator *vreg;
+ const char *name;
+ u32 min_uV;
+ u32 max_uV;
+};
+
+struct sensor_regulator lis3dh_acc_vreg[] = {
+ {NULL, "vdd", 1700000, 3600000},
+ {NULL, "vddio", 1700000, 3600000},
+};
+
+static int lis3dh_acc_config_regulator(struct lis3dh_acc_data *acc, bool on)
+{
+ int rc = 0, i;
+ int num_reg = sizeof(lis3dh_acc_vreg) / sizeof(struct sensor_regulator);
+
+ if (on) {
+ for (i = 0; i < num_reg; i++) {
+ lis3dh_acc_vreg[i].vreg =
+ regulator_get(&acc->client->dev,
+ lis3dh_acc_vreg[i].name);
+ if (IS_ERR(lis3dh_acc_vreg[i].vreg)) {
+ rc = PTR_ERR(lis3dh_acc_vreg[i].vreg);
+ pr_err("%s:regulator get failed rc=%d\n",
+ __func__, rc);
+ goto error_vdd;
+ }
+
+ if (regulator_count_voltages(
+ lis3dh_acc_vreg[i].vreg) > 0) {
+ rc = regulator_set_voltage(
+ lis3dh_acc_vreg[i].vreg,
+ lis3dh_acc_vreg[i].min_uV,
+ lis3dh_acc_vreg[i].max_uV);
+ if (rc) {
+ pr_err("%s: set voltage failed rc=%d\n",
+ __func__, rc);
+ regulator_put(lis3dh_acc_vreg[i].vreg);
+ goto error_vdd;
+ }
+ }
+
+ rc = regulator_enable(lis3dh_acc_vreg[i].vreg);
+ if (rc) {
+ pr_err("%s: regulator_enable failed rc =%d\n",
+ __func__, rc);
+ if (regulator_count_voltages(
+ lis3dh_acc_vreg[i].vreg) > 0) {
+ regulator_set_voltage(
+ lis3dh_acc_vreg[i].vreg, 0,
+ lis3dh_acc_vreg[i].max_uV);
+ }
+ regulator_put(lis3dh_acc_vreg[i].vreg);
+ goto error_vdd;
+ }
+ }
+ return rc;
+ } else {
+ i = num_reg;
+ }
+
+error_vdd:
+ while (--i >= 0) {
+ if (regulator_count_voltages(lis3dh_acc_vreg[i].vreg) > 0) {
+ regulator_set_voltage(lis3dh_acc_vreg[i].vreg, 0,
+ lis3dh_acc_vreg[i].max_uV);
+ }
+ regulator_disable(lis3dh_acc_vreg[i].vreg);
+ regulator_put(lis3dh_acc_vreg[i].vreg);
+ }
+ return rc;
+}
+
+static int lis3dh_acc_i2c_read(struct lis3dh_acc_data *acc,
+ u8 *buf, int len)
+{
+ int err;
+ int tries = 0;
+
+ struct i2c_msg msgs[] = {
+ {
+ .addr = acc->client->addr,
+ .flags = acc->client->flags & I2C_M_TEN,
+ .len = 1,
+ .buf = buf,
+ },
+ {
+ .addr = acc->client->addr,
+ .flags = (acc->client->flags & I2C_M_TEN) | I2C_M_RD,
+ .len = len,
+ .buf = buf,
+ },
+ };
+
+ do {
+ err = i2c_transfer(acc->client->adapter, msgs, 2);
+ if (err != 2)
+ msleep_interruptible(I2C_RETRY_DELAY);
+ } while ((err != 2) && (++tries < I2C_RETRIES));
+
+ if (err != 2) {
+ dev_err(&acc->client->dev, "read transfer error\n");
+ err = -EIO;
+ } else {
+ err = 0;
+ }
+
+ return err;
+}
+
+static int lis3dh_acc_i2c_write(struct lis3dh_acc_data *acc, u8 *buf, int len)
+{
+ int err;
+ int tries = 0;
+
+ struct i2c_msg msgs[] = {
+ {
+ .addr = acc->client->addr,
+ .flags = acc->client->flags & I2C_M_TEN,
+ .len = len + 1,
+ .buf = buf,
+ },
+ };
+
+ do {
+ err = i2c_transfer(acc->client->adapter, msgs, 1);
+ if (err != 1)
+ msleep_interruptible(I2C_RETRY_DELAY);
+ } while ((err != 1) && (++tries < I2C_RETRIES));
+
+ if (err != 1) {
+ dev_err(&acc->client->dev, "write transfer error\n");
+ err = -EIO;
+ } else {
+ err = 0;
+ }
+
+ return err;
+}
+
+static int lis3dh_acc_hw_init(struct lis3dh_acc_data *acc)
+{
+ int err = -1;
+ u8 buf[7];
+
+ printk(KERN_INFO "%s: hw init start\n", LIS3DH_ACC_DEV_NAME);
+
+ buf[0] = WHO_AM_I;
+ err = lis3dh_acc_i2c_read(acc, buf, 1);
+ if (err < 0) {
+ dev_warn(&acc->client->dev,
+ "Error reading WHO_AM_I: is device available/working?\n");
+ goto err_firstread;
+ } else
+ acc->hw_working = 1;
+ if (buf[0] != WHOAMI_LIS3DH_ACC) {
+ dev_err(&acc->client->dev,
+ "device unknown. Expected: 0x%x, Replies: 0x%x\n",
+ WHOAMI_LIS3DH_ACC, buf[0]);
+ err = -1; /* choose the right coded error */
+ goto err_unknown_device;
+ }
+
+ buf[0] = CTRL_REG1;
+ buf[1] = acc->resume_state[RES_CTRL_REG1];
+ err = lis3dh_acc_i2c_write(acc, buf, 1);
+ if (err < 0)
+ goto err_resume_state;
+
+ buf[0] = TEMP_CFG_REG;
+ buf[1] = acc->resume_state[RES_TEMP_CFG_REG];
+ err = lis3dh_acc_i2c_write(acc, buf, 1);
+ if (err < 0)
+ goto err_resume_state;
+
+ buf[0] = FIFO_CTRL_REG;
+ buf[1] = acc->resume_state[RES_FIFO_CTRL_REG];
+ err = lis3dh_acc_i2c_write(acc, buf, 1);
+ if (err < 0)
+ goto err_resume_state;
+
+ buf[0] = (I2C_AUTO_INCREMENT | TT_THS);
+ buf[1] = acc->resume_state[RES_TT_THS];
+ buf[2] = acc->resume_state[RES_TT_LIM];
+ buf[3] = acc->resume_state[RES_TT_TLAT];
+ buf[4] = acc->resume_state[RES_TT_TW];
+ err = lis3dh_acc_i2c_write(acc, buf, 4);
+ if (err < 0)
+ goto err_resume_state;
+ buf[0] = TT_CFG;
+ buf[1] = acc->resume_state[RES_TT_CFG];
+ err = lis3dh_acc_i2c_write(acc, buf, 1);
+ if (err < 0)
+ goto err_resume_state;
+
+ buf[0] = (I2C_AUTO_INCREMENT | INT_THS1);
+ buf[1] = acc->resume_state[RES_INT_THS1];
+ buf[2] = acc->resume_state[RES_INT_DUR1];
+ err = lis3dh_acc_i2c_write(acc, buf, 2);
+ if (err < 0)
+ goto err_resume_state;
+ buf[0] = INT_CFG1;
+ buf[1] = acc->resume_state[RES_INT_CFG1];
+ err = lis3dh_acc_i2c_write(acc, buf, 1);
+ if (err < 0)
+ goto err_resume_state;
+
+
+ buf[0] = (I2C_AUTO_INCREMENT | CTRL_REG2);
+ buf[1] = acc->resume_state[RES_CTRL_REG2];
+ buf[2] = acc->resume_state[RES_CTRL_REG3];
+ buf[3] = acc->resume_state[RES_CTRL_REG4];
+ buf[4] = acc->resume_state[RES_CTRL_REG5];
+ buf[5] = acc->resume_state[RES_CTRL_REG6];
+ err = lis3dh_acc_i2c_write(acc, buf, 5);
+ if (err < 0)
+ goto err_resume_state;
+
+ acc->hw_initialized = 1;
+ printk(KERN_INFO "%s: hw init done\n", LIS3DH_ACC_DEV_NAME);
+ return 0;
+
+err_firstread:
+ acc->hw_working = 0;
+err_unknown_device:
+err_resume_state:
+ acc->hw_initialized = 0;
+ dev_err(&acc->client->dev, "hw init error 0x%x,0x%x: %d\n", buf[0],
+ buf[1], err);
+ return err;
+}
+
+static void lis3dh_acc_device_power_off(struct lis3dh_acc_data *acc)
+{
+ int err;
+ u8 buf[2] = { CTRL_REG1, LIS3DH_ACC_PM_OFF };
+
+ err = lis3dh_acc_i2c_write(acc, buf, 1);
+ if (err < 0)
+ dev_err(&acc->client->dev, "soft power off failed: %d\n", err);
+
+ if (acc->pdata->gpio_int1)
+ disable_irq_nosync(acc->irq1);
+ if (acc->pdata->gpio_int2)
+ disable_irq_nosync(acc->irq2);
+
+ lis3dh_acc_config_regulator(acc, false);
+
+ if (acc->hw_initialized) {
+ if (acc->pdata->gpio_int1)
+ disable_irq_nosync(acc->irq1);
+ if (acc->pdata->gpio_int2)
+ disable_irq_nosync(acc->irq2);
+ acc->hw_initialized = 0;
+ }
+}
+
+static int lis3dh_acc_device_power_on(struct lis3dh_acc_data *acc)
+{
+ int err = -1;
+
+ err = lis3dh_acc_config_regulator(acc, true);
+ if (err < 0) {
+ dev_err(&acc->client->dev,
+ "power_on failed: %d\n", err);
+ return err;
+ }
+
+ if (acc->pdata->gpio_int1 >= 0)
+ enable_irq(acc->irq1);
+ if (acc->pdata->gpio_int2 >= 0)
+ enable_irq(acc->irq2);
+
+ msleep(20);
+
+ if (!acc->hw_initialized) {
+ err = lis3dh_acc_hw_init(acc);
+ if (acc->hw_working == 1 && err < 0) {
+ lis3dh_acc_device_power_off(acc);
+ return err;
+ }
+ }
+
+ if (acc->hw_initialized) {
+ if (acc->pdata->gpio_int1 >= 0)
+ enable_irq(acc->irq1);
+ if (acc->pdata->gpio_int2 >= 0)
+ enable_irq(acc->irq2);
+ }
+ return 0;
+}
+
+static irqreturn_t lis3dh_acc_isr1(int irq, void *dev)
+{
+ struct lis3dh_acc_data *acc = dev;
+
+ disable_irq_nosync(irq);
+ queue_work(acc->irq1_work_queue, &acc->irq1_work);
+#ifdef DEBUG
+ printk(KERN_INFO "%s: isr1 queued\n", LIS3DH_ACC_DEV_NAME);
+#endif
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t lis3dh_acc_isr2(int irq, void *dev)
+{
+ struct lis3dh_acc_data *acc = dev;
+
+ disable_irq_nosync(irq);
+ queue_work(acc->irq2_work_queue, &acc->irq2_work);
+#ifdef DEBUG
+ printk(KERN_INFO "%s: isr2 queued\n", LIS3DH_ACC_DEV_NAME);
+#endif
+ return IRQ_HANDLED;
+}
+
+static void lis3dh_acc_irq1_work_func(struct work_struct *work)
+{
+
+ struct lis3dh_acc_data *acc =
+ container_of(work, struct lis3dh_acc_data, irq1_work);
+ /* TODO add interrupt service procedure.
+ ie:lis3dh_acc_get_int1_source(acc); */
+ ;
+ /* */
+ printk(KERN_INFO "%s: IRQ1 triggered\n", LIS3DH_ACC_DEV_NAME);
+ goto exit;
+exit:
+ enable_irq(acc->irq1);
+}
+
+static void lis3dh_acc_irq2_work_func(struct work_struct *work)
+{
+
+ struct lis3dh_acc_data *acc =
+ container_of(work, struct lis3dh_acc_data, irq2_work);
+ /* TODO add interrupt service procedure.
+ ie:lis3dh_acc_get_tap_source(acc); */
+ ;
+ /* */
+ printk(KERN_INFO "%s: IRQ2 triggered\n", LIS3DH_ACC_DEV_NAME);
+ goto exit;
+exit:
+ enable_irq(acc->irq2);
+}
+
+int lis3dh_acc_update_g_range(struct lis3dh_acc_data *acc, u8 new_g_range)
+{
+ int err = -1;
+
+ u8 sensitivity;
+ u8 buf[2];
+ u8 updated_val;
+ u8 init_val;
+ u8 new_val;
+ u8 mask = LIS3DH_ACC_FS_MASK | HIGH_RESOLUTION;
+
+ switch (new_g_range) {
+ case LIS3DH_ACC_G_2G:
+
+ sensitivity = SENSITIVITY_2G;
+ break;
+ case LIS3DH_ACC_G_4G:
+
+ sensitivity = SENSITIVITY_4G;
+ break;
+ case LIS3DH_ACC_G_8G:
+
+ sensitivity = SENSITIVITY_8G;
+ break;
+ case LIS3DH_ACC_G_16G:
+
+ sensitivity = SENSITIVITY_16G;
+ break;
+ default:
+ dev_err(&acc->client->dev, "invalid g range requested: %u\n",
+ new_g_range);
+ return -EINVAL;
+ }
+
+ if (atomic_read(&acc->enabled)) {
+ /* Updates configuration register 4,
+ * which contains g range setting */
+ buf[0] = CTRL_REG4;
+ err = lis3dh_acc_i2c_read(acc, buf, 1);
+ if (err < 0)
+ goto error;
+ init_val = buf[0];
+ acc->resume_state[RES_CTRL_REG4] = init_val;
+ new_val = new_g_range | HIGH_RESOLUTION;
+ updated_val = ((mask & new_val) | ((~mask) & init_val));
+ buf[1] = updated_val;
+ buf[0] = CTRL_REG4;
+ err = lis3dh_acc_i2c_write(acc, buf, 1);
+ if (err < 0)
+ goto error;
+ acc->resume_state[RES_CTRL_REG4] = updated_val;
+ acc->sensitivity = sensitivity;
+ }
+
+
+ return err;
+error:
+ dev_err(&acc->client->dev, "update g range failed 0x%x,0x%x: %d\n",
+ buf[0], buf[1], err);
+
+ return err;
+}
+
+int lis3dh_acc_update_odr(struct lis3dh_acc_data *acc, int poll_interval_ms)
+{
+ int err = -1;
+ int i;
+ u8 config[2];
+
+ /* Following, looks for the longest possible odr interval scrolling the
+ * odr_table vector from the end (shortest interval) backward (longest
+ * interval), to support the poll_interval requested by the system.
+ * It must be the longest interval lower then the poll interval.*/
+ for (i = ARRAY_SIZE(lis3dh_acc_odr_table) - 1; i >= 0; i--) {
+ if (lis3dh_acc_odr_table[i].cutoff_ms <= poll_interval_ms)
+ break;
+ }
+ config[1] = lis3dh_acc_odr_table[i].mask;
+
+ config[1] |= LIS3DH_ACC_ENABLE_ALL_AXES;
+
+ /* If device is currently enabled, we need to write new
+ * configuration out to it */
+ if (atomic_read(&acc->enabled)) {
+ config[0] = CTRL_REG1;
+ err = lis3dh_acc_i2c_write(acc, config, 1);
+ if (err < 0)
+ goto error;
+ acc->resume_state[RES_CTRL_REG1] = config[1];
+ }
+
+ return err;
+
+error:
+ dev_err(&acc->client->dev, "update odr failed 0x%x,0x%x: %d\n",
+ config[0], config[1], err);
+
+ return err;
+}
+
+
+
+static int lis3dh_acc_register_write(struct lis3dh_acc_data *acc, u8 *buf,
+ u8 reg_address, u8 new_value)
+{
+ int err = -1;
+
+ /* Sets configuration register at reg_address
+ * NOTE: this is a straight overwrite */
+ buf[0] = reg_address;
+ buf[1] = new_value;
+ err = lis3dh_acc_i2c_write(acc, buf, 1);
+ if (err < 0)
+ return err;
+ return err;
+}
+
+static int lis3dh_acc_get_acceleration_data(struct lis3dh_acc_data *acc,
+ int *xyz)
+{
+ int err = -1;
+ /* Data bytes from hardware xL, xH, yL, yH, zL, zH */
+ u8 acc_data[6];
+ /* x,y,z hardware data */
+ s16 hw_d[3] = { 0 };
+
+ acc_data[0] = (I2C_AUTO_INCREMENT | AXISDATA_REG);
+ err = lis3dh_acc_i2c_read(acc, acc_data, 6);
+ if (err < 0)
+ return err;
+
+ hw_d[0] = (((s16) ((acc_data[1] << 8) | acc_data[0])) >> 4);
+ hw_d[1] = (((s16) ((acc_data[3] << 8) | acc_data[2])) >> 4);
+ hw_d[2] = (((s16) ((acc_data[5] << 8) | acc_data[4])) >> 4);
+
+ hw_d[0] = hw_d[0] * acc->sensitivity;
+ hw_d[1] = hw_d[1] * acc->sensitivity;
+ hw_d[2] = hw_d[2] * acc->sensitivity;
+
+
+ xyz[0] = ((acc->pdata->negate_x) ? (-hw_d[acc->pdata->axis_map_x])
+ : (hw_d[acc->pdata->axis_map_x]));
+ xyz[1] = ((acc->pdata->negate_y) ? (-hw_d[acc->pdata->axis_map_y])
+ : (hw_d[acc->pdata->axis_map_y]));
+ xyz[2] = ((acc->pdata->negate_z) ? (-hw_d[acc->pdata->axis_map_z])
+ : (hw_d[acc->pdata->axis_map_z]));
+
+ #ifdef DEBUG
+ /*
+ printk(KERN_INFO "%s read x=%d, y=%d, z=%d\n",
+ LIS3DH_ACC_DEV_NAME, xyz[0], xyz[1], xyz[2]);
+ */
+ #endif
+ return err;
+}
+
+static void lis3dh_acc_report_values(struct lis3dh_acc_data *acc,
+ int *xyz)
+{
+ input_report_abs(acc->input_dev, ABS_X, xyz[0]);
+ input_report_abs(acc->input_dev, ABS_Y, xyz[1]);
+ input_report_abs(acc->input_dev, ABS_Z, xyz[2]);
+ input_sync(acc->input_dev);
+}
+
+static int lis3dh_acc_enable(struct lis3dh_acc_data *acc)
+{
+ int err;
+
+ if (!atomic_cmpxchg(&acc->enabled, 0, 1)) {
+ err = lis3dh_acc_device_power_on(acc);
+ if (err < 0) {
+ atomic_set(&acc->enabled, 0);
+ return err;
+ }
+ schedule_delayed_work(&acc->input_work,
+ msecs_to_jiffies(acc->pdata->poll_interval));
+ }
+
+ return 0;
+}
+
+static int lis3dh_acc_disable(struct lis3dh_acc_data *acc)
+{
+ if (atomic_cmpxchg(&acc->enabled, 1, 0)) {
+ cancel_delayed_work_sync(&acc->input_work);
+ lis3dh_acc_device_power_off(acc);
+ }
+
+ return 0;
+}
+
+
+static ssize_t read_single_reg(struct device *dev, char *buf, u8 reg)
+{
+ ssize_t ret;
+ struct lis3dh_acc_data *acc = dev_get_drvdata(dev);
+ int err;
+
+ u8 data = reg;
+ err = lis3dh_acc_i2c_read(acc, &data, 1);
+ if (err < 0)
+ return err;
+ ret = snprintf(buf, 4, "0x%02x\n", data);
+ return ret;
+
+}
+
+static int write_reg(struct device *dev, const char *buf, u8 reg,
+ u8 mask, int resumeIndex)
+{
+ int err = -1;
+ struct lis3dh_acc_data *acc = dev_get_drvdata(dev);
+ u8 x[2];
+ u8 new_val;
+ unsigned long val;
+
+ if (kstrtoul(buf, 16, &val))
+ return -EINVAL;
+
+ new_val = ((u8) val & mask);
+ x[0] = reg;
+ x[1] = new_val;
+ err = lis3dh_acc_register_write(acc, x, reg, new_val);
+ if (err < 0)
+ return err;
+ acc->resume_state[resumeIndex] = new_val;
+ return err;
+}
+
+static ssize_t attr_get_polling_rate(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int val;
+ struct lis3dh_acc_data *acc = dev_get_drvdata(dev);
+ mutex_lock(&acc->lock);
+ val = acc->pdata->poll_interval;
+ mutex_unlock(&acc->lock);
+ return snprintf(buf, 8, "%d\n", val);
+}
+
+static ssize_t attr_set_polling_rate(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct lis3dh_acc_data *acc = dev_get_drvdata(dev);
+ unsigned long interval_ms;
+
+ if (kstrtoul(buf, 10, &interval_ms))
+ return -EINVAL;
+ if (!interval_ms)
+ return -EINVAL;
+ mutex_lock(&acc->lock);
+ acc->pdata->poll_interval = interval_ms;
+ lis3dh_acc_update_odr(acc, interval_ms);
+ mutex_unlock(&acc->lock);
+ return size;
+}
+
+static ssize_t attr_get_range(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ char val;
+ struct lis3dh_acc_data *acc = dev_get_drvdata(dev);
+ char range = 2;
+ mutex_lock(&acc->lock);
+ val = acc->pdata->g_range ;
+ switch (val) {
+ case LIS3DH_ACC_G_2G:
+ range = 2;
+ break;
+ case LIS3DH_ACC_G_4G:
+ range = 4;
+ break;
+ case LIS3DH_ACC_G_8G:
+ range = 8;
+ break;
+ case LIS3DH_ACC_G_16G:
+ range = 16;
+ break;
+ }
+ mutex_unlock(&acc->lock);
+ return snprintf(buf, 4, "%d\n", range);
+}
+
+static ssize_t attr_set_range(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct lis3dh_acc_data *acc = dev_get_drvdata(dev);
+ unsigned long val;
+ if (kstrtoul(buf, 10, &val))
+ return -EINVAL;
+ mutex_lock(&acc->lock);
+ acc->pdata->g_range = val;
+ lis3dh_acc_update_g_range(acc, val);
+ mutex_unlock(&acc->lock);
+ return size;
+}
+
+static ssize_t attr_get_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lis3dh_acc_data *acc = dev_get_drvdata(dev);
+ int val = atomic_read(&acc->enabled);
+ return snprintf(buf, sizeof(val) + 2, "%d\n", val);
+}
+
+static ssize_t attr_set_enable(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct lis3dh_acc_data *acc = dev_get_drvdata(dev);
+ unsigned long val;
+
+ if (kstrtoul(buf, 10, &val))
+ return -EINVAL;
+
+ if (val)
+ lis3dh_acc_enable(acc);
+ else
+ lis3dh_acc_disable(acc);
+
+ return size;
+}
+
+static ssize_t attr_set_intconfig1(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ return write_reg(dev, buf, INT_CFG1, NO_MASK, RES_INT_CFG1);
+}
+
+static ssize_t attr_get_intconfig1(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return read_single_reg(dev, buf, INT_CFG1);
+}
+
+static ssize_t attr_set_duration1(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ return write_reg(dev, buf, INT_DUR1, INT1_DURATION_MASK, RES_INT_DUR1);
+}
+
+static ssize_t attr_get_duration1(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return read_single_reg(dev, buf, INT_DUR1);
+}
+
+static ssize_t attr_set_thresh1(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ return write_reg(dev, buf, INT_THS1, INT1_THRESHOLD_MASK, RES_INT_THS1);
+}
+
+static ssize_t attr_get_thresh1(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return read_single_reg(dev, buf, INT_THS1);
+}
+
+static ssize_t attr_get_source1(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return read_single_reg(dev, buf, INT_SRC1);
+}
+
+static ssize_t attr_set_click_cfg(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ return write_reg(dev, buf, TT_CFG, TAP_CFG_MASK, RES_TT_CFG);
+}
+
+static ssize_t attr_get_click_cfg(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+ return read_single_reg(dev, buf, TT_CFG);
+}
+
+static ssize_t attr_get_click_source(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return read_single_reg(dev, buf, TT_SRC);
+}
+
+static ssize_t attr_set_click_ths(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ return write_reg(dev, buf, TT_THS, TAP_THS_MASK, RES_TT_THS);
+}
+
+static ssize_t attr_get_click_ths(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return read_single_reg(dev, buf, TT_THS);
+}
+
+static ssize_t attr_set_click_tlim(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ return write_reg(dev, buf, TT_LIM, TAP_TLIM_MASK, RES_TT_LIM);
+}
+
+static ssize_t attr_get_click_tlim(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return read_single_reg(dev, buf, TT_LIM);
+}
+
+static ssize_t attr_set_click_tlat(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ return write_reg(dev, buf, TT_TLAT, TAP_TLAT_MASK, RES_TT_TLAT);
+}
+
+static ssize_t attr_get_click_tlat(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return read_single_reg(dev, buf, TT_TLAT);
+}
+
+static ssize_t attr_set_click_tw(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ return write_reg(dev, buf, TT_TLAT, TAP_TW_MASK, RES_TT_TLAT);
+}
+
+static ssize_t attr_get_click_tw(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return read_single_reg(dev, buf, TT_TLAT);
+}
+
+
+#ifdef DEBUG
+/* PAY ATTENTION: These DEBUG funtions don't manage resume_state */
+static ssize_t attr_reg_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int rc;
+ struct lis3dh_acc_data *acc = dev_get_drvdata(dev);
+ u8 x[2];
+ unsigned long val;
+
+ if (kstrtoul(buf, 16, &val))
+ return -EINVAL;
+ mutex_lock(&acc->lock);
+ x[0] = acc->reg_addr;
+ mutex_unlock(&acc->lock);
+ x[1] = val;
+ rc = lis3dh_acc_i2c_write(acc, x, 1);
+ /*TODO: error need to be managed */
+ return size;
+}
+
+static ssize_t attr_reg_get(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ ssize_t ret;
+ struct lis3dh_acc_data *acc = dev_get_drvdata(dev);
+ int rc;
+ u8 data;
+
+ mutex_lock(&acc->lock);
+ data = acc->reg_addr;
+ mutex_unlock(&acc->lock);
+ rc = lis3dh_acc_i2c_read(acc, &data, 1);
+ /* TODO: error need to be managed */
+ ret = snprintf(buf, 8, "0x%02x\n", data);
+ return ret;
+}
+
+static ssize_t attr_addr_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct lis3dh_acc_data *acc = dev_get_drvdata(dev);
+ unsigned long val;
+ if (kstrtoul(buf, 16, &val))
+ return -EINVAL;
+ mutex_lock(&acc->lock);
+ acc->reg_addr = val;
+ mutex_unlock(&acc->lock);
+ return size;
+}
+#endif
+
+static struct device_attribute attributes[] = {
+
+ __ATTR(pollrate_ms, 0666, attr_get_polling_rate,
+ attr_set_polling_rate),
+ __ATTR(range, 0666, attr_get_range, attr_set_range),
+ __ATTR(enable, 0666, attr_get_enable, attr_set_enable),
+ __ATTR(int1_config, 0666, attr_get_intconfig1, attr_set_intconfig1),
+ __ATTR(int1_duration, 0666, attr_get_duration1, attr_set_duration1),
+ __ATTR(int1_threshold, 0666, attr_get_thresh1, attr_set_thresh1),
+ __ATTR(int1_source, 0444, attr_get_source1, NULL),
+ __ATTR(click_config, 0666, attr_get_click_cfg, attr_set_click_cfg),
+ __ATTR(click_source, 0444, attr_get_click_source, NULL),
+ __ATTR(click_threshold, 0666, attr_get_click_ths, attr_set_click_ths),
+ __ATTR(click_timelimit, 0666, attr_get_click_tlim,
+ attr_set_click_tlim),
+ __ATTR(click_timelatency, 0666, attr_get_click_tlat,
+ attr_set_click_tlat),
+ __ATTR(click_timewindow, 0666, attr_get_click_tw, attr_set_click_tw),
+
+#ifdef DEBUG
+ __ATTR(reg_value, 0666, attr_reg_get, attr_reg_set),
+ __ATTR(reg_addr, 0222, NULL, attr_addr_set),
+#endif
+};
+
+static int create_sysfs_interfaces(struct device *dev)
+{
+ int i;
+ int err;
+ for (i = 0; i < ARRAY_SIZE(attributes); i++) {
+ err = device_create_file(dev, attributes + i);
+ if (err)
+ goto error;
+ }
+ return 0;
+
+error:
+ for ( ; i >= 0; i--)
+ device_remove_file(dev, attributes + i);
+ dev_err(dev, "%s:Unable to create interface\n", __func__);
+ return err;
+}
+
+static int remove_sysfs_interfaces(struct device *dev)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(attributes); i++)
+ device_remove_file(dev, attributes + i);
+ return 0;
+}
+
+static void lis3dh_acc_input_work_func(struct work_struct *work)
+{
+ struct lis3dh_acc_data *acc;
+
+ int xyz[3] = { 0 };
+ int err;
+
+ acc = container_of((struct delayed_work *)work,
+ struct lis3dh_acc_data, input_work);
+
+ mutex_lock(&acc->lock);
+ err = lis3dh_acc_get_acceleration_data(acc, xyz);
+ if (err < 0)
+ dev_err(&acc->client->dev, "get_acceleration_data failed\n");
+ else
+ lis3dh_acc_report_values(acc, xyz);
+
+ schedule_delayed_work(&acc->input_work, msecs_to_jiffies(
+ acc->pdata->poll_interval));
+ mutex_unlock(&acc->lock);
+}
+
+int lis3dh_acc_input_open(struct input_dev *input)
+{
+ struct lis3dh_acc_data *acc = input_get_drvdata(input);
+
+ return lis3dh_acc_enable(acc);
+}
+
+void lis3dh_acc_input_close(struct input_dev *dev)
+{
+ struct lis3dh_acc_data *acc = input_get_drvdata(dev);
+
+ lis3dh_acc_disable(acc);
+}
+
+static int lis3dh_acc_validate_pdata(struct lis3dh_acc_data *acc)
+{
+ acc->pdata->poll_interval = max(acc->pdata->poll_interval,
+ acc->pdata->min_interval);
+
+ if (acc->pdata->axis_map_x > 2 ||
+ acc->pdata->axis_map_y > 2 ||
+ acc->pdata->axis_map_z > 2) {
+ dev_err(&acc->client->dev,
+ "invalid axis_map value x:%u y:%u z%u\n",
+ acc->pdata->axis_map_x,
+ acc->pdata->axis_map_y, acc->pdata->axis_map_z);
+ return -EINVAL;
+ }
+
+ /* Only allow 0 and 1 for negation boolean flag */
+ if (acc->pdata->negate_x > 1 || acc->pdata->negate_y > 1
+ || acc->pdata->negate_z > 1) {
+ dev_err(&acc->client->dev,
+ "invalid negate value x:%u y:%u z:%u\n",
+ acc->pdata->negate_x,
+ acc->pdata->negate_y, acc->pdata->negate_z);
+ return -EINVAL;
+ }
+
+ /* Enforce minimum polling interval */
+ if (acc->pdata->poll_interval < acc->pdata->min_interval) {
+ dev_err(&acc->client->dev, "minimum poll interval violated\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int lis3dh_acc_input_init(struct lis3dh_acc_data *acc)
+{
+ int err;
+
+ INIT_DELAYED_WORK(&acc->input_work, lis3dh_acc_input_work_func);
+ acc->input_dev = input_allocate_device();
+ if (!acc->input_dev) {
+ err = -ENOMEM;
+ dev_err(&acc->client->dev, "input device allocation failed\n");
+ goto err0;
+ }
+
+ acc->input_dev->open = lis3dh_acc_input_open;
+ acc->input_dev->close = lis3dh_acc_input_close;
+ acc->input_dev->name = LIS3DH_ACC_DEV_NAME;
+ acc->input_dev->id.bustype = BUS_I2C;
+ acc->input_dev->dev.parent = &acc->client->dev;
+
+ input_set_drvdata(acc->input_dev, acc);
+
+ set_bit(EV_ABS, acc->input_dev->evbit);
+ /* next is used for interruptA sources data if the case */
+ set_bit(ABS_MISC, acc->input_dev->absbit);
+ /* next is used for interruptB sources data if the case */
+ set_bit(ABS_WHEEL, acc->input_dev->absbit);
+
+ input_set_abs_params(acc->input_dev, ABS_X, -G_MAX, G_MAX, FUZZ, FLAT);
+ input_set_abs_params(acc->input_dev, ABS_Y, -G_MAX, G_MAX, FUZZ, FLAT);
+ input_set_abs_params(acc->input_dev, ABS_Z, -G_MAX, G_MAX, FUZZ, FLAT);
+ /* next is used for interruptA sources data if the case */
+ input_set_abs_params(acc->input_dev, ABS_MISC, INT_MIN, INT_MAX, 0, 0);
+ /* next is used for interruptB sources data if the case */
+ input_set_abs_params(acc->input_dev, ABS_WHEEL, INT_MIN, INT_MAX, 0, 0);
+
+
+ err = input_register_device(acc->input_dev);
+ if (err) {
+ dev_err(&acc->client->dev,
+ "unable to register input device %s\n",
+ acc->input_dev->name);
+ goto err1;
+ }
+
+ return 0;
+
+err1:
+ input_free_device(acc->input_dev);
+err0:
+ return err;
+}
+
+static void lis3dh_acc_input_cleanup(struct lis3dh_acc_data *acc)
+{
+ input_unregister_device(acc->input_dev);
+ input_free_device(acc->input_dev);
+}
+
+static int lis3dh_acc_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+
+ struct lis3dh_acc_data *acc;
+
+ int err = -1;
+
+ pr_info("%s: probe start.\n", LIS3DH_ACC_DEV_NAME);
+
+ if (client->dev.platform_data == NULL) {
+ dev_err(&client->dev, "platform data is NULL. exiting.\n");
+ err = -ENODEV;
+ goto exit_check_functionality_failed;
+ }
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "client not i2c capable\n");
+ err = -ENODEV;
+ goto exit_check_functionality_failed;
+ }
+
+ /*
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA)) {
+ dev_err(&client->dev, "client not smb-i2c capable:2\n");
+ err = -EIO;
+ goto exit_check_functionality_failed;
+ }
+
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_I2C_BLOCK)) {
+ dev_err(&client->dev, "client not smb-i2c capable:3\n");
+ err = -EIO;
+ goto exit_check_functionality_failed;
+ }
+ */
+
+ acc = kzalloc(sizeof(struct lis3dh_acc_data), GFP_KERNEL);
+ if (acc == NULL) {
+ err = -ENOMEM;
+ dev_err(&client->dev,
+ "failed to allocate memory for module data: "
+ "%d\n", err);
+ goto exit_check_functionality_failed;
+ }
+
+
+ mutex_init(&acc->lock);
+ mutex_lock(&acc->lock);
+
+ acc->client = client;
+ i2c_set_clientdata(client, acc);
+
+ acc->pdata = kmalloc(sizeof(*acc->pdata), GFP_KERNEL);
+ if (acc->pdata == NULL) {
+ err = -ENOMEM;
+ dev_err(&client->dev,
+ "failed to allocate memory for pdata: %d\n",
+ err);
+ goto err_mutexunlock;
+ }
+
+ memcpy(acc->pdata, client->dev.platform_data, sizeof(*acc->pdata));
+
+ err = lis3dh_acc_validate_pdata(acc);
+ if (err < 0) {
+ dev_err(&client->dev, "failed to validate platform data\n");
+ goto exit_kfree_pdata;
+ }
+
+
+ if (acc->pdata->init) {
+ err = acc->pdata->init();
+ if (err < 0) {
+ dev_err(&client->dev, "init failed: %d\n", err);
+ goto err_pdata_init;
+ }
+ }
+
+ if (acc->pdata->gpio_int1 >= 0) {
+ acc->irq1 = gpio_to_irq(acc->pdata->gpio_int1);
+ printk(KERN_INFO "%s: %s has set irq1 to irq: %d\n",
+ LIS3DH_ACC_DEV_NAME, __func__, acc->irq1);
+ printk(KERN_INFO "%s: %s has mapped irq1 on gpio: %d\n",
+ LIS3DH_ACC_DEV_NAME, __func__,
+ acc->pdata->gpio_int1);
+ }
+
+ if (acc->pdata->gpio_int2 >= 0) {
+ acc->irq2 = gpio_to_irq(acc->pdata->gpio_int2);
+ printk(KERN_INFO "%s: %s has set irq2 to irq: %d\n",
+ LIS3DH_ACC_DEV_NAME, __func__, acc->irq2);
+ printk(KERN_INFO "%s: %s has mapped irq2 on gpio: %d\n",
+ LIS3DH_ACC_DEV_NAME, __func__,
+ acc->pdata->gpio_int2);
+ }
+
+ memset(acc->resume_state, 0, ARRAY_SIZE(acc->resume_state));
+
+ acc->resume_state[RES_CTRL_REG1] = LIS3DH_ACC_ENABLE_ALL_AXES;
+ acc->resume_state[RES_CTRL_REG2] = 0x00;
+ acc->resume_state[RES_CTRL_REG3] = 0x00;
+ acc->resume_state[RES_CTRL_REG4] = 0x00;
+ acc->resume_state[RES_CTRL_REG5] = 0x00;
+ acc->resume_state[RES_CTRL_REG6] = 0x00;
+
+ acc->resume_state[RES_TEMP_CFG_REG] = 0x00;
+ acc->resume_state[RES_FIFO_CTRL_REG] = 0x00;
+ acc->resume_state[RES_INT_CFG1] = 0x00;
+ acc->resume_state[RES_INT_THS1] = 0x00;
+ acc->resume_state[RES_INT_DUR1] = 0x00;
+
+ acc->resume_state[RES_TT_CFG] = 0x00;
+ acc->resume_state[RES_TT_THS] = 0x00;
+ acc->resume_state[RES_TT_LIM] = 0x00;
+ acc->resume_state[RES_TT_TLAT] = 0x00;
+ acc->resume_state[RES_TT_TW] = 0x00;
+
+ err = lis3dh_acc_device_power_on(acc);
+ if (err < 0) {
+ dev_err(&client->dev, "power on failed: %d\n", err);
+ goto err_pdata_init;
+ }
+
+ atomic_set(&acc->enabled, 1);
+
+ err = lis3dh_acc_update_g_range(acc, acc->pdata->g_range);
+ if (err < 0) {
+ dev_err(&client->dev, "update_g_range failed\n");
+ goto err_power_off;
+ }
+
+ err = lis3dh_acc_update_odr(acc, acc->pdata->poll_interval);
+ if (err < 0) {
+ dev_err(&client->dev, "update_odr failed\n");
+ goto err_power_off;
+ }
+
+ err = lis3dh_acc_input_init(acc);
+ if (err < 0) {
+ dev_err(&client->dev, "input init failed\n");
+ goto err_power_off;
+ }
+
+
+ err = create_sysfs_interfaces(&client->dev);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "device LIS3DH_ACC_DEV_NAME sysfs register failed\n");
+ goto err_input_cleanup;
+ }
+
+ lis3dh_acc_device_power_off(acc);
+
+ /* As default, do not report information */
+ atomic_set(&acc->enabled, 0);
+
+ if (acc->pdata->gpio_int1 >= 0) {
+ INIT_WORK(&acc->irq1_work, lis3dh_acc_irq1_work_func);
+ acc->irq1_work_queue =
+ create_singlethread_workqueue("lis3dh_acc_wq1");
+ if (!acc->irq1_work_queue) {
+ err = -ENOMEM;
+ dev_err(&client->dev,
+ "cannot create work queue1: %d\n", err);
+ goto err_remove_sysfs_int;
+ }
+ err = request_irq(acc->irq1, lis3dh_acc_isr1,
+ IRQF_TRIGGER_RISING, "lis3dh_acc_irq1", acc);
+ if (err < 0) {
+ dev_err(&client->dev, "request irq1 failed: %d\n", err);
+ goto err_destoyworkqueue1;
+ }
+ disable_irq_nosync(acc->irq1);
+ }
+
+ if (acc->pdata->gpio_int2 >= 0) {
+ INIT_WORK(&acc->irq2_work, lis3dh_acc_irq2_work_func);
+ acc->irq2_work_queue =
+ create_singlethread_workqueue("lis3dh_acc_wq2");
+ if (!acc->irq2_work_queue) {
+ err = -ENOMEM;
+ dev_err(&client->dev,
+ "cannot create work queue2: %d\n", err);
+ goto err_free_irq1;
+ }
+ err = request_irq(acc->irq2, lis3dh_acc_isr2,
+ IRQF_TRIGGER_RISING, "lis3dh_acc_irq2", acc);
+ if (err < 0) {
+ dev_err(&client->dev, "request irq2 failed: %d\n", err);
+ goto err_destoyworkqueue2;
+ }
+ disable_irq_nosync(acc->irq2);
+ }
+
+
+
+ mutex_unlock(&acc->lock);
+
+ dev_info(&client->dev, "%s: probed\n", LIS3DH_ACC_DEV_NAME);
+
+ return 0;
+
+err_destoyworkqueue2:
+ if (acc->pdata->gpio_int2 >= 0)
+ destroy_workqueue(acc->irq2_work_queue);
+err_free_irq1:
+ free_irq(acc->irq1, acc);
+err_destoyworkqueue1:
+ if (acc->pdata->gpio_int1 >= 0)
+ destroy_workqueue(acc->irq1_work_queue);
+err_remove_sysfs_int:
+ remove_sysfs_interfaces(&client->dev);
+err_input_cleanup:
+ lis3dh_acc_input_cleanup(acc);
+err_power_off:
+ lis3dh_acc_device_power_off(acc);
+err_pdata_init:
+ if (acc->pdata->exit)
+ acc->pdata->exit();
+exit_kfree_pdata:
+ kfree(acc->pdata);
+err_mutexunlock:
+ mutex_unlock(&acc->lock);
+ kfree(acc);
+exit_check_functionality_failed:
+ printk(KERN_ERR "%s: Driver Init failed\n", LIS3DH_ACC_DEV_NAME);
+ return err;
+}
+
+static int __devexit lis3dh_acc_remove(struct i2c_client *client)
+{
+ struct lis3dh_acc_data *acc = i2c_get_clientdata(client);
+
+ if (acc->pdata->gpio_int1 >= 0) {
+ free_irq(acc->irq1, acc);
+ gpio_free(acc->pdata->gpio_int1);
+ destroy_workqueue(acc->irq1_work_queue);
+ }
+
+ if (acc->pdata->gpio_int2 >= 0) {
+ free_irq(acc->irq2, acc);
+ gpio_free(acc->pdata->gpio_int2);
+ destroy_workqueue(acc->irq2_work_queue);
+ }
+
+ lis3dh_acc_input_cleanup(acc);
+ lis3dh_acc_device_power_off(acc);
+ remove_sysfs_interfaces(&client->dev);
+
+ if (acc->pdata->exit)
+ acc->pdata->exit();
+ kfree(acc->pdata);
+ kfree(acc);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int lis3dh_acc_resume(struct i2c_client *client)
+{
+ struct lis3dh_acc_data *acc = i2c_get_clientdata(client);
+
+ if (acc->on_before_suspend)
+ return lis3dh_acc_enable(acc);
+ return 0;
+}
+
+static int lis3dh_acc_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ struct lis3dh_acc_data *acc = i2c_get_clientdata(client);
+
+ acc->on_before_suspend = atomic_read(&acc->enabled);
+ return lis3dh_acc_disable(acc);
+}
+#else
+#define lis3dh_acc_suspend NULL
+#define lis3dh_acc_resume NULL
+#endif /* CONFIG_PM */
+
+static const struct i2c_device_id lis3dh_acc_id[]
+ = { { LIS3DH_ACC_DEV_NAME, 0 }, { }, };
+
+MODULE_DEVICE_TABLE(i2c, lis3dh_acc_id);
+
+static struct i2c_driver lis3dh_acc_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = LIS3DH_ACC_DEV_NAME,
+ },
+ .probe = lis3dh_acc_probe,
+ .remove = __devexit_p(lis3dh_acc_remove),
+ .suspend = lis3dh_acc_suspend,
+ .resume = lis3dh_acc_resume,
+ .id_table = lis3dh_acc_id,
+};
+
+static int __init lis3dh_acc_init(void)
+{
+ printk(KERN_INFO "%s accelerometer driver: init\n",
+ LIS3DH_ACC_DEV_NAME);
+ return i2c_add_driver(&lis3dh_acc_driver);
+}
+
+static void __exit lis3dh_acc_exit(void)
+{
+#ifdef DEBUG
+ printk(KERN_INFO "%s accelerometer driver exit\n",
+ LIS3DH_ACC_DEV_NAME);
+#endif /* DEBUG */
+ i2c_del_driver(&lis3dh_acc_driver);
+ return;
+}
+
+module_init(lis3dh_acc_init);
+module_exit(lis3dh_acc_exit);
+
+MODULE_DESCRIPTION("lis3dh digital accelerometer sysfs driver");
+MODULE_AUTHOR("Matteo Dameno, Carmine Iascone, Samuel Huo, STMicroelectronics");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/leds/leds-pm8xxx.c b/drivers/leds/leds-pm8xxx.c
index 3261037..04041e4 100644
--- a/drivers/leds/leds-pm8xxx.c
+++ b/drivers/leds/leds-pm8xxx.c
@@ -323,12 +323,17 @@
}
static void
-led_rgb_set(struct pm8xxx_led_data *led, enum led_brightness value)
+led_rgb_write(struct pm8xxx_led_data *led, u16 addr, enum led_brightness value)
{
int rc;
u8 val, mask;
- rc = pm8xxx_readb(led->dev->parent, SSBI_REG_ADDR_RGB_CNTL2, &val);
+ if (led->id != PM8XXX_ID_RGB_LED_BLUE &&
+ led->id != PM8XXX_ID_RGB_LED_RED &&
+ led->id != PM8XXX_ID_RGB_LED_GREEN)
+ return;
+
+ rc = pm8xxx_readb(led->dev->parent, addr, &val);
if (rc) {
dev_err(led->cdev.dev, "can't read rgb ctrl register rc=%d\n",
rc);
@@ -354,12 +359,24 @@
else
val &= ~mask;
- rc = pm8xxx_writeb(led->dev->parent, SSBI_REG_ADDR_RGB_CNTL2, val);
+ rc = pm8xxx_writeb(led->dev->parent, addr, val);
if (rc < 0)
dev_err(led->cdev.dev, "can't set rgb led %d level rc=%d\n",
led->id, rc);
}
+static void
+led_rgb_set(struct pm8xxx_led_data *led, enum led_brightness value)
+{
+ if (value) {
+ led_rgb_write(led, SSBI_REG_ADDR_RGB_CNTL1, value);
+ led_rgb_write(led, SSBI_REG_ADDR_RGB_CNTL2, value);
+ } else {
+ led_rgb_write(led, SSBI_REG_ADDR_RGB_CNTL2, value);
+ led_rgb_write(led, SSBI_REG_ADDR_RGB_CNTL1, value);
+ }
+}
+
static int pm8xxx_led_pwm_work(struct pm8xxx_led_data *led)
{
int duty_us;
@@ -369,12 +386,23 @@
duty_us = (led->pwm_period_us * led->cdev.brightness) /
LED_FULL;
rc = pwm_config(led->pwm_dev, duty_us, led->pwm_period_us);
- if (led->cdev.brightness)
+ if (led->cdev.brightness) {
+ led_rgb_write(led, SSBI_REG_ADDR_RGB_CNTL1,
+ led->cdev.brightness);
rc = pwm_enable(led->pwm_dev);
- else
+ } else {
pwm_disable(led->pwm_dev);
+ led_rgb_write(led, SSBI_REG_ADDR_RGB_CNTL1,
+ led->cdev.brightness);
+ }
} else {
+ if (led->cdev.brightness)
+ led_rgb_write(led, SSBI_REG_ADDR_RGB_CNTL1,
+ led->cdev.brightness);
rc = pm8xxx_pwm_lut_enable(led->pwm_dev, led->cdev.brightness);
+ if (!led->cdev.brightness)
+ led_rgb_write(led, SSBI_REG_ADDR_RGB_CNTL1,
+ led->cdev.brightness);
}
return rc;
@@ -658,35 +686,6 @@
return 0;
}
-static int __devinit init_rgb_led(struct pm8xxx_led_data *led)
-{
- int rc;
- u8 val;
-
- rc = pm8xxx_readb(led->dev->parent, SSBI_REG_ADDR_RGB_CNTL1, &val);
- if (rc) {
- dev_err(led->cdev.dev, "can't read rgb ctrl1 register rc=%d\n",
- rc);
- return rc;
- }
-
- switch (led->id) {
- case PM8XXX_ID_RGB_LED_RED:
- val |= PM8XXX_DRV_RGB_RED_LED;
- break;
- case PM8XXX_ID_RGB_LED_GREEN:
- val |= PM8XXX_DRV_RGB_GREEN_LED;
- break;
- case PM8XXX_ID_RGB_LED_BLUE:
- val |= PM8XXX_DRV_RGB_BLUE_LED;
- break;
- default:
- return -EINVAL;
- }
-
- return pm8xxx_writeb(led->dev->parent, SSBI_REG_ADDR_RGB_CNTL1, val);
-}
-
static int __devinit get_init_value(struct pm8xxx_led_data *led, u8 *val)
{
int rc, offset;
@@ -717,12 +716,6 @@
case PM8XXX_ID_RGB_LED_RED:
case PM8XXX_ID_RGB_LED_GREEN:
case PM8XXX_ID_RGB_LED_BLUE:
- rc = init_rgb_led(led);
- if (rc) {
- dev_err(led->cdev.dev, "can't initialize rgb rc=%d\n",
- rc);
- return rc;
- }
addr = SSBI_REG_ADDR_RGB_CNTL1;
break;
default:
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index 9ad79e9..071d209 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -168,6 +168,7 @@
struct dmx_ts_feed {
int is_filtering; /* Set to non-zero when filtering in progress */
struct dmx_demux *parent; /* Back-pointer */
+ const struct dvb_ringbuffer *buffer;
void *priv; /* Pointer to private data of the API client */
int (*set) (struct dmx_ts_feed *feed,
u16 pid,
@@ -184,6 +185,8 @@
struct dmx_buffer_status *dmx_buffer_status);
int (*data_ready_cb)(struct dmx_ts_feed *feed,
dmx_ts_data_ready_cb callback);
+ int (*notify_data_read)(struct dmx_ts_feed *feed,
+ u32 bytes_num);
};
/*--------------------------------------------------------------------------*/
@@ -195,6 +198,7 @@
u8 filter_mask [DMX_MAX_FILTER_SIZE];
u8 filter_mode [DMX_MAX_FILTER_SIZE];
struct dmx_section_feed* parent; /* Back-pointer */
+ const struct dvb_ringbuffer *buffer;
void* priv; /* Pointer to private data of the API client */
};
@@ -227,6 +231,8 @@
int (*stop_filtering) (struct dmx_section_feed* feed);
int (*data_ready_cb)(struct dmx_section_feed *feed,
dmx_section_data_ready_cb callback);
+ int (*notify_data_read)(struct dmx_section_filter *filter,
+ u32 bytes_num);
};
/*--------------------------------------------------------------------------*/
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 433e796..8353f6f 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -60,6 +60,35 @@
return dvb_ringbuffer_write(buf, src, len);
}
+static inline void dvb_dmxdev_notify_data_read(struct dmxdev_filter *filter,
+ int bytes_read)
+{
+ if (!filter)
+ return;
+
+ if (filter->type == DMXDEV_TYPE_SEC) {
+ if (filter->feed.sec->notify_data_read)
+ filter->feed.sec->notify_data_read(
+ filter->filter.sec,
+ bytes_read);
+ } else {
+ struct dmxdev_feed *feed;
+
+ /*
+ * All feeds of same demux-handle share the same output
+ * buffer, it is enough to notify on the buffer status
+ * on one of the feeds
+ */
+ feed = list_first_entry(&filter->feed.ts,
+ struct dmxdev_feed, next);
+
+ if (feed->ts->notify_data_read)
+ feed->ts->notify_data_read(
+ feed->ts,
+ bytes_read);
+ }
+}
+
static inline u32 dvb_dmxdev_advance_event_idx(u32 index)
{
index++;
@@ -460,6 +489,7 @@
}
dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
dvb_dmxdev_flush_events(&dmxdev->dvr_output_events);
+ dmxdev->dvr_feeds_count = 0;
dvbdev->readers--;
} else if (!dvbdev->writers) {
@@ -719,9 +749,22 @@
buf, count, ppos);
if (res > 0) {
+ dvb_dmxdev_notify_data_read(dmxdev->dvr_feed, res);
spin_lock_irq(&dmxdev->lock);
dvb_dmxdev_update_events(&dmxdev->dvr_output_events, res);
spin_unlock_irq(&dmxdev->lock);
+ } else if (res == -EOVERFLOW) {
+ /*
+ * When buffer overflowed, demux-dev flushed the
+ * buffer and marked the buffer in error state.
+ * Data from underlying driver is discarded until
+ * user gets notified that buffer has overflowed.
+ * Now that the user is notified, notify underlying
+ * driver that data was flushed from output buffer.
+ */
+ dvb_dmxdev_notify_data_read(dmxdev->dvr_feed,
+ dmxdev->dvr_flush_data_len);
+ dmxdev->dvr_flush_data_len = 0;
}
return res;
@@ -873,8 +916,20 @@
res = dvb_dmxdev_remove_event(&dmxdev->dvr_output_events, event);
- if (event->type == DMX_EVENT_BUFFER_OVERFLOW)
+ if (event->type == DMX_EVENT_BUFFER_OVERFLOW) {
+ /*
+ * When buffer overflowed, demux-dev flushed the
+ * buffer and marked the buffer in error state.
+ * Data from underlying driver is discarded until
+ * user gets notified that buffer has overflowed.
+ * Now that the user is notified, notify underlying
+ * driver that data was flushed from output buffer.
+ */
+ dvb_dmxdev_notify_data_read(dmxdev->dvr_feed,
+ dmxdev->dvr_flush_data_len);
+ dmxdev->dvr_flush_data_len = 0;
dmxdev->dvr_buffer.error = 0;
+ }
spin_unlock_irq(&dmxdev->lock);
@@ -899,7 +954,23 @@
spin_lock_irq(lock);
dmx_buffer_status->error = buf->error;
- buf->error = 0;
+ if (buf->error) {
+ if (buf->error == -EOVERFLOW) {
+ /*
+ * When buffer overflowed, demux-dev flushed the
+ * buffer and marked the buffer in error state.
+ * Data from underlying driver is discarded until
+ * user gets notified that buffer has overflowed.
+ * Now that the user is notified, notify underlying
+ * driver that data was flushed from output buffer.
+ */
+ dvb_dmxdev_notify_data_read(dmxdev->dvr_feed,
+ dmxdev->dvr_flush_data_len);
+ dmxdev->dvr_flush_data_len = 0;
+ }
+
+ buf->error = 0;
+ }
dmx_buffer_status->fullness = dvb_ringbuffer_avail(buf);
dmx_buffer_status->free_bytes = dvb_ringbuffer_free(buf);
@@ -931,6 +1002,7 @@
DVB_RINGBUFFER_SKIP(&dmxdev->dvr_buffer, bytes_count);
+ dvb_dmxdev_notify_data_read(dmxdev->dvr_feed, bytes_count);
spin_lock_irq(&dmxdev->lock);
dvb_dmxdev_update_events(&dmxdev->dvr_output_events, bytes_count);
spin_unlock_irq(&dmxdev->lock);
@@ -1183,27 +1255,39 @@
struct dmxdev_feed *feed;
int ret;
- /* Ask for status of decoder's buffer from underlying HW */
- list_for_each_entry(feed, &dmxdevfilter->feed.ts,
- next) {
- if (feed->ts->get_decoder_buff_status)
- ret = feed->ts->get_decoder_buff_status(
- feed->ts,
- dmx_buffer_status);
- else
- ret = -ENODEV;
+ /* Only one feed should be in the list in case of decoder */
+ feed = list_first_entry(&dmxdevfilter->feed.ts,
+ struct dmxdev_feed, next);
- /*
- * There should not be more than one ts feed
- * in the list as this is DECODER feed.
- */
- spin_unlock_irq(&dmxdevfilter->dev->lock);
- return ret;
- }
+ /* Ask for status of decoder's buffer from underlying HW */
+ if (feed->ts->get_decoder_buff_status)
+ ret = feed->ts->get_decoder_buff_status(
+ feed->ts,
+ dmx_buffer_status);
+ else
+ ret = -ENODEV;
+
+ spin_unlock_irq(&dmxdevfilter->dev->lock);
+ return ret;
}
dmx_buffer_status->error = buf->error;
- buf->error = 0;
+ if (buf->error) {
+ if (buf->error == -EOVERFLOW) {
+ /*
+ * When buffer overflowed, demux-dev flushed the
+ * buffer and marked the buffer in error state.
+ * Data from underlying driver is discarded until
+ * user gets notified that buffer has overflowed.
+ * Now that the user is notified, notify underlying
+ * driver that data was flushed from output buffer.
+ */
+ dvb_dmxdev_notify_data_read(dmxdevfilter,
+ dmxdevfilter->flush_data_len);
+ dmxdevfilter->flush_data_len = 0;
+ }
+ buf->error = 0;
+ }
dmx_buffer_status->fullness = dvb_ringbuffer_avail(buf);
dmx_buffer_status->free_bytes = dvb_ringbuffer_free(buf);
@@ -1234,6 +1318,7 @@
DVB_RINGBUFFER_SKIP(&dmxdevfilter->buffer, bytes_count);
+ dvb_dmxdev_notify_data_read(dmxdevfilter, bytes_count);
spin_lock_irq(&dmxdevfilter->dev->lock);
dvb_dmxdev_update_events(&dmxdevfilter->events, bytes_count);
spin_unlock_irq(&dmxdevfilter->dev->lock);
@@ -1252,8 +1337,20 @@
res = dvb_dmxdev_remove_event(&dmxdevfilter->events, event);
- if (event->type == DMX_EVENT_BUFFER_OVERFLOW)
+ if (event->type == DMX_EVENT_BUFFER_OVERFLOW) {
+ /*
+ * When buffer overflowed, demux-dev flushed the
+ * buffer and marked the buffer in error state.
+ * Data from underlying driver is discarded until
+ * user gets notified that buffer has overflowed.
+ * Now that the user is notified, notify underlying
+ * driver that data was flushed from output buffer.
+ */
+ dvb_dmxdev_notify_data_read(dmxdevfilter,
+ dmxdevfilter->flush_data_len);
+ dmxdevfilter->flush_data_len = 0;
dmxdevfilter->buffer.error = 0;
+ }
spin_unlock_irq(&dmxdevfilter->dev->lock);
@@ -1334,6 +1431,8 @@
buffer2_len);
if (ret < 0) {
+ dmxdevfilter->flush_data_len =
+ dvb_ringbuffer_avail(&dmxdevfilter->buffer);
dvb_dmxdev_flush_output(&dmxdevfilter->buffer,
&dmxdevfilter->events);
dmxdevfilter->buffer.error = ret;
@@ -1372,6 +1471,7 @@
struct dmxdev_events_queue *events;
struct dmx_filter_event event;
int ret;
+ u32 *flush_data_len;
spin_lock(&dmxdevfilter->dev->lock);
if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {
@@ -1383,9 +1483,11 @@
|| dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) {
buffer = &dmxdevfilter->buffer;
events = &dmxdevfilter->events;
+ flush_data_len = &dmxdevfilter->flush_data_len;
} else {
buffer = &dmxdevfilter->dev->dvr_buffer;
events = &dmxdevfilter->dev->dvr_output_events;
+ flush_data_len = &dmxdevfilter->dev->dvr_flush_data_len;
}
if (buffer->error) {
@@ -1435,6 +1537,8 @@
ret = dvb_dmxdev_buffer_write(buffer, buffer2,
buffer2_len);
if (ret < 0) {
+ *flush_data_len =
+ dvb_ringbuffer_avail(&dmxdevfilter->buffer);
dvb_dmxdev_flush_output(buffer, events);
buffer->error = ret;
@@ -1507,6 +1611,8 @@
if ((DMX_OVERRUN_ERROR == dmx_data_ready->status) ||
(dmx_data_ready->data_length > free)) {
+ dmxdevfilter->flush_data_len =
+ dvb_ringbuffer_avail(&dmxdevfilter->buffer);
dvb_dmxdev_flush_output(&dmxdevfilter->buffer,
&dmxdevfilter->events);
@@ -1548,6 +1654,7 @@
struct dvb_ringbuffer *buffer;
struct dmxdev_events_queue *events;
struct dmx_filter_event event;
+ u32 *flush_data_len;
int free;
spin_lock(&dmxdevfilter->dev->lock);
@@ -1560,9 +1667,11 @@
if (dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) {
buffer = &dmxdevfilter->buffer;
events = &dmxdevfilter->events;
+ flush_data_len = &dmxdevfilter->flush_data_len;
} else {
buffer = &dmxdevfilter->dev->dvr_buffer;
events = &dmxdevfilter->dev->dvr_output_events;
+ flush_data_len = &dmxdevfilter->dev->dvr_flush_data_len;
}
if (dmx_data_ready->status == DMX_OK_PCR) {
@@ -1592,6 +1701,8 @@
if ((DMX_OVERRUN_ERROR == dmx_data_ready->status) ||
(dmx_data_ready->data_length > free)) {
+ *flush_data_len =
+ dvb_ringbuffer_avail(&dmxdevfilter->buffer);
dvb_dmxdev_flush_output(buffer, events);
dprintk("dmxdev: buffer overflow\n");
@@ -1761,6 +1872,12 @@
case DMXDEV_TYPE_PES:
dvb_dmxdev_feed_stop(dmxdevfilter);
demux = dmxdevfilter->dev->demux;
+ if (dmxdevfilter->params.pes.output == DMX_OUT_TS_TAP) {
+ dmxdevfilter->dev->dvr_feeds_count--;
+ if (!dmxdevfilter->dev->dvr_feeds_count)
+ dmxdevfilter->dev->dvr_feed = NULL;
+ }
+
list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) {
demux->release_ts_feed(demux, feed->ts);
feed->ts = NULL;
@@ -1844,6 +1961,15 @@
tsfeed = feed->ts;
tsfeed->priv = filter;
+ if (filter->params.pes.output == DMX_OUT_TS_TAP) {
+ tsfeed->buffer = &dmxdev->dvr_buffer;
+ if (!dmxdev->dvr_feeds_count)
+ dmxdev->dvr_feed = filter;
+ dmxdev->dvr_feeds_count++;
+ } else {
+ tsfeed->buffer = &filter->buffer;
+ }
+
if (tsfeed->data_ready_cb) {
ret = tsfeed->data_ready_cb(tsfeed, dvb_dmxdev_ts_event_cb);
@@ -1979,6 +2105,7 @@
}
(*secfilter)->priv = filter;
+ (*secfilter)->buffer = &filter->buffer;
memcpy(&((*secfilter)->filter_value[3]),
&(para->filter.filter[1]), DMX_FILTER_SIZE - 1);
@@ -2278,9 +2405,22 @@
buf, count, ppos);
if (ret > 0) {
+ dvb_dmxdev_notify_data_read(dmxdevfilter, ret);
spin_lock_irq(&dmxdevfilter->dev->lock);
dvb_dmxdev_update_events(&dmxdevfilter->events, ret);
spin_unlock_irq(&dmxdevfilter->dev->lock);
+ } else if (ret == -EOVERFLOW) {
+ /*
+ * When buffer overflowed, demux-dev flushed the
+ * buffer and marked the buffer in error state.
+ * Data from underlying driver is discarded until
+ * user gets notified that buffer has overflowed.
+ * Now that the user is notified, notify underlying
+ * driver that data was flushed from output buffer.
+ */
+ dvb_dmxdev_notify_data_read(dmxdevfilter->dev->dvr_feed,
+ dmxdevfilter->flush_data_len);
+ dmxdevfilter->flush_data_len = 0;
}
mutex_unlock(&dmxdevfilter->mutex);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index 6fa7054..9fd900e 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -113,6 +113,7 @@
enum dmxdev_state state;
struct dmxdev *dev;
struct dvb_ringbuffer buffer;
+ u32 flush_data_len;
struct mutex mutex;
@@ -153,6 +154,9 @@
struct dvb_ringbuffer dvr_buffer;
struct dmxdev_events_queue dvr_output_events;
+ struct dmxdev_filter *dvr_feed;
+ u32 dvr_flush_data_len;
+ int dvr_feeds_count;
struct dvb_ringbuffer dvr_input_buffer;
struct workqueue_struct *dvr_input_workqueue;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 0be6a22..0bdf6cb 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -1137,6 +1137,7 @@
(*ts_feed)->set_indexing_params = dmx_ts_set_indexing_params;
(*ts_feed)->get_decoder_buff_status = dmx_ts_feed_decoder_buff_status;
(*ts_feed)->data_ready_cb = dmx_ts_feed_data_ready_cb;
+ (*ts_feed)->notify_data_read = NULL;
if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
feed->state = DMX_STATE_FREE;
@@ -1434,6 +1435,7 @@
(*feed)->stop_filtering = dmx_section_feed_stop_filtering;
(*feed)->release_filter = dmx_section_feed_release_filter;
(*feed)->data_ready_cb = dmx_section_feed_data_ready_cb;
+ (*feed)->notify_data_read = NULL;
mutex_unlock(&dvbdmx->mutex);
return 0;
diff --git a/drivers/media/video/msm/gemini/msm_gemini_sync.c b/drivers/media/video/msm/gemini/msm_gemini_sync.c
index e878329..97bb611 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_sync.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_sync.c
@@ -218,6 +218,7 @@
return -EAGAIN;
}
+ memset(&ctrl_cmd, 0, sizeof(struct msm_gemini_ctrl_cmd));
ctrl_cmd.type = buf_p->vbuf.type;
kfree(buf_p);
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 3222f905..29aba08 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -888,7 +888,10 @@
goto msm_cam_server_begin_session_failed;
}
pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
-
+ if (!pmctl) {
+ pr_err("%s mctl ptr is null ", __func__);
+ goto msm_cam_server_begin_session_failed;
+ }
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
pmctl->client = msm_ion_client_create(-1, "camera");
kref_init(&pmctl->refcount);
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 4bbc47c..fd5591c 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -437,7 +437,7 @@
/* open sub devices - once only*/
if (!p_mctl->opencnt) {
struct msm_sensor_csi_info csi_info;
- uint32_t csid_version;
+ uint32_t csid_version = 0;
wake_lock(&p_mctl->wake_lock);
csid_core = camdev->csid_core;
@@ -1327,6 +1327,10 @@
WARN_ON(pctx != f->private_data);
pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
+ if (!pmctl) {
+ pr_err("%s mctl ptr is null ", __func__);
+ return -EINVAL;
+ }
if (!pcam_inst->vbqueue_initialized) {
pmctl->mctl_vbqueue_init(pcam_inst, &pcam_inst->vid_bufq,
V4L2_BUF_TYPE_VIDEO_CAPTURE);
@@ -1351,6 +1355,10 @@
WARN_ON(pctx != f->private_data);
pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
+ if (!pmctl) {
+ pr_err("%s mctl ptr is null ", __func__);
+ return -EINVAL;
+ }
if (!pcam_inst->vbqueue_initialized) {
pmctl->mctl_vbqueue_init(pcam_inst, &pcam_inst->vid_bufq,
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index 38179e6..aa2b19d 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -4754,7 +4754,8 @@
return rc;
clk_enable_failed:
- regulator_disable(axi_ctrl->fs_vfe);
+ if (axi_ctrl->fs_vfe)
+ regulator_disable(axi_ctrl->fs_vfe);
fs_failed:
iounmap(axi_ctrl->share_ctrl->vfebase);
axi_ctrl->share_ctrl->vfebase = NULL;
@@ -4932,12 +4933,14 @@
pr_err("%s: base address unmapped\n", __func__);
return -EFAULT;
}
+ memset(&cfgcmd, 0, sizeof(struct msm_vfe_cfg_cmd));
if (NULL != arg) {
if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
ERR_COPY_FROM_USER();
return -EFAULT;
}
}
+ memset(&vfecmd, 0, sizeof(struct msm_isp_cmd));
if (NULL != cfgcmd.value) {
if (copy_from_user(&vfecmd,
(void __user *)(cfgcmd.value),
diff --git a/drivers/media/video/msm/msm_vpe.c b/drivers/media/video/msm/msm_vpe.c
index 58fc153..5990ca7 100644
--- a/drivers/media/video/msm/msm_vpe.c
+++ b/drivers/media/video/msm/msm_vpe.c
@@ -545,7 +545,8 @@
return rc;
vpe_clk_failed:
- regulator_disable(vpe_ctrl->fs_vpe);
+ if (vpe_ctrl->fs_vpe)
+ regulator_disable(vpe_ctrl->fs_vpe);
vpe_fs_failed:
disable_irq(vpe_ctrl->vpeirq->start);
vpe_ctrl->state = VPE_STATE_IDLE;
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index 715b4e7..deab77b 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -1783,7 +1783,7 @@
* the individual irq lookup table.... */
irq_req->irq_idx =
get_irq_idx_from_camhw_idx(irq_req->cam_hw_idx);
- if (irq_req->cam_hw_idx < 0) {
+ if (irq_req->irq_idx < 0) {
pr_err("%s Invalid hw index %d ", __func__,
irq_req->cam_hw_idx);
return -EINVAL;
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 64a0516..72c6685 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -63,6 +63,30 @@
"Model 2",
NULL
};
+
+static const char *const h263_level[] = {
+ "1.0",
+ "2.0",
+ "3.0",
+ "4.0",
+ "4.5",
+ "5.0",
+ "6.0",
+ "7.0",
+};
+
+static const char *const h263_profile[] = {
+ "Baseline",
+ "H320 Coding",
+ "Backward Compatible",
+ "ISWV2",
+ "ISWV3",
+ "High Compression",
+ "Internet",
+ "Interlace",
+ "High Latency",
+};
+
static const struct msm_vidc_ctrl msm_venc_ctrls[] = {
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE,
@@ -212,10 +236,48 @@
.minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
.maximum = V4L2_MPEG_VIDEO_H264_LEVEL_5_1,
.default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
- .step = 1,
+ .step = 0,
.menu_skip_mask = 0,
},
{
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE,
+ .name = "H263 Profile",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY)
+ ),
+ .qmenu = h263_profile,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL,
+ .name = "H263 Level",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0)
+ ),
+ .qmenu = h263_level,
+ },
+ {
.id = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
.name = "Rotation",
.type = V4L2_CTRL_TYPE_MENU,
@@ -410,8 +472,11 @@
venc_h264_profile_level = {HAL_H264_PROFILE_BASELINE,
HAL_H264_LEVEL_1};
static struct hal_profile_level
- venc_mpeg4_profile_level = {HAL_H264_PROFILE_BASELINE,
- HAL_H264_LEVEL_1};
+ venc_mpeg4_profile_level = {HAL_MPEG4_PROFILE_SIMPLE,
+ HAL_MPEG4_LEVEL_0};
+static struct hal_profile_level
+ venc_h263_profile_level = {HAL_H263_PROFILE_BASELINE,
+ HAL_H263_LEVEL_10};
static struct hal_h264_entropy_control
venc_h264_entropy_control = {HAL_H264_ENTROPY_CAVLC,
HAL_H264_CABAC_MODEL_0};
@@ -904,6 +969,84 @@
pr_debug("\nLevel: %d\n",
profile_level.level);
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
+ property_id =
+ HAL_PARAM_PROFILE_LEVEL_CURRENT;
+
+ switch (control.value) {
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE:
+ control.value = HAL_H263_PROFILE_BASELINE;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING:
+ control.value = HAL_H263_PROFILE_H320CODING;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE:
+ control.value = HAL_H263_PROFILE_BACKWARDCOMPATIBLE;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2:
+ control.value = HAL_H263_PROFILE_ISWV2;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3:
+ control.value = HAL_H263_PROFILE_ISWV3;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION:
+ control.value = HAL_H263_PROFILE_HIGHCOMPRESSION;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET:
+ control.value = HAL_H263_PROFILE_INTERNET;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE:
+ control.value = HAL_H263_PROFILE_INTERLACE;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY:
+ control.value = HAL_H263_PROFILE_HIGHLATENCY;
+ break;
+ default:
+ break;
+ }
+ profile_level.profile = control.value;
+ venc_h263_profile_level.profile = control.value;
+ profile_level.level = venc_h263_profile_level.level;
+ pdata = &profile_level;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL:
+ property_id =
+ HAL_PARAM_PROFILE_LEVEL_CURRENT;
+
+ switch (control.value) {
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0:
+ control.value = HAL_H263_LEVEL_10;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0:
+ control.value = HAL_H263_LEVEL_20;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0:
+ control.value = HAL_H263_LEVEL_30;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0:
+ control.value = HAL_H263_LEVEL_40;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_5:
+ control.value = HAL_H263_LEVEL_45;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0:
+ control.value = HAL_H263_LEVEL_50;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0:
+ control.value = HAL_H263_LEVEL_60;
+ break;
+ case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0:
+ control.value = HAL_H263_LEVEL_70;
+ break;
+ default:
+ break;
+ }
+
+ profile_level.level = control.value;
+ venc_h263_profile_level.level = control.value;
+ profile_level.profile = venc_h263_profile_level.profile;
+ pdata = &profile_level;
+ break;
case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
property_id =
HAL_CONFIG_VPE_OPERATIONS;
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index 98e2fd9..01e1201 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -1113,7 +1113,6 @@
{
struct vcap_client_data *c_data = to_client_data(file->private_data);
struct vcap_dev *dev = c_data->dev;
- unsigned long flags;
int rc;
unsigned long rate;
long rate_rc;
@@ -1126,14 +1125,14 @@
switch (c_data->op_mode) {
case VC_VCAP_OP:
- spin_lock_irqsave(&dev->dev_slock, flags);
+ mutex_lock(&dev->dev_mutex);
if (dev->vc_resource) {
pr_err("VCAP Err: %s: VC resource taken", __func__);
- spin_unlock_irqrestore(&dev->dev_slock, flags);
+ mutex_unlock(&dev->dev_mutex);
return -EBUSY;
}
dev->vc_resource = 1;
- spin_unlock_irqrestore(&dev->dev_slock, flags);
+ mutex_unlock(&dev->dev_mutex);
c_data->dev->vc_client = c_data;
@@ -1179,14 +1178,14 @@
goto free_res;
break;
case VP_VCAP_OP:
- spin_lock_irqsave(&dev->dev_slock, flags);
+ mutex_lock(&dev->dev_mutex);
if (dev->vp_resource) {
pr_err("VCAP Err: %s: VP resource taken", __func__);
- spin_unlock_irqrestore(&dev->dev_slock, flags);
+ mutex_unlock(&dev->dev_mutex);
return -EBUSY;
}
dev->vp_resource = 1;
- spin_unlock_irqrestore(&dev->dev_slock, flags);
+ mutex_unlock(&dev->dev_mutex);
c_data->dev->vp_client = c_data;
rate = 160000000;
@@ -1240,16 +1239,16 @@
goto s_on_deinit_nr_buf;
break;
case VC_AND_VP_VCAP_OP:
- spin_lock_irqsave(&dev->dev_slock, flags);
+ mutex_lock(&dev->dev_mutex);
if (dev->vc_resource || dev->vp_resource) {
pr_err("VCAP Err: %s: VC/VP resource taken",
__func__);
- spin_unlock_irqrestore(&dev->dev_slock, flags);
+ mutex_unlock(&dev->dev_mutex);
return -EBUSY;
}
dev->vc_resource = 1;
dev->vp_resource = 1;
- spin_unlock_irqrestore(&dev->dev_slock, flags);
+ mutex_unlock(&dev->dev_mutex);
c_data->dev->vc_client = c_data;
c_data->dev->vp_client = c_data;
@@ -1347,7 +1346,7 @@
s_on_deinit_m_buf:
deinit_motion_buf(c_data);
free_res:
- spin_lock_irqsave(&dev->dev_slock, flags);
+ mutex_lock(&dev->dev_mutex);
if (c_data->op_mode == VC_VCAP_OP) {
dev->vc_resource = 0;
c_data->dev->vc_client = NULL;
@@ -1360,7 +1359,7 @@
dev->vc_resource = 0;
dev->vp_resource = 0;
}
- spin_unlock_irqrestore(&dev->dev_slock, flags);
+ mutex_unlock(&dev->dev_mutex);
return rc;
}
@@ -1381,7 +1380,6 @@
int streamoff_work(struct vcap_client_data *c_data)
{
struct vcap_dev *dev = c_data->dev;
- unsigned long flags;
int rc;
switch (c_data->op_mode) {
case VC_VCAP_OP:
@@ -1390,14 +1388,14 @@
__func__);
return -EBUSY;
}
- spin_lock_irqsave(&dev->dev_slock, flags);
+ mutex_lock(&dev->dev_mutex);
if (!dev->vc_resource) {
pr_err("VCAP Err: %s: VC res not acquired", __func__);
- spin_unlock_irqrestore(&dev->dev_slock, flags);
+ mutex_unlock(&dev->dev_mutex);
return -EBUSY;
}
dev->vc_resource = 0;
- spin_unlock_irqrestore(&dev->dev_slock, flags);
+ mutex_unlock(&dev->dev_mutex);
rc = vb2_streamoff(&c_data->vc_vidq,
V4L2_BUF_TYPE_VIDEO_CAPTURE);
if (rc >= 0) {
@@ -1406,19 +1404,24 @@
}
return rc;
case VP_VCAP_OP:
+ if (!dev->vp_dummy_complete) {
+ pr_err("VCAP Err: %s: VP dummy read not complete",
+ __func__);
+ return -EINVAL;
+ }
if (c_data != dev->vp_client) {
pr_err("VCAP Err: %s: VP held by other client",
__func__);
return -EBUSY;
}
- spin_lock_irqsave(&dev->dev_slock, flags);
+ mutex_lock(&dev->dev_mutex);
if (!dev->vp_resource) {
pr_err("VCAP Err: %s: VP res not acquired", __func__);
- spin_unlock_irqrestore(&dev->dev_slock, flags);
+ mutex_unlock(&dev->dev_mutex);
return -EBUSY;
}
dev->vp_resource = 0;
- spin_unlock_irqrestore(&dev->dev_slock, flags);
+ mutex_unlock(&dev->dev_mutex);
rc = streamoff_validate_q(&c_data->vp_in_vidq);
if (rc < 0)
return rc;
@@ -1444,21 +1447,26 @@
atomic_set(&c_data->dev->vp_enabled, 0);
return rc;
case VC_AND_VP_VCAP_OP:
+ if (!dev->vp_dummy_complete) {
+ pr_err("VCAP Err: %s: VP dummy read not complete",
+ __func__);
+ return -EINVAL;
+ }
if (c_data != dev->vp_client || c_data != dev->vc_client) {
pr_err("VCAP Err: %s: VC/VP held by other client",
__func__);
return -EBUSY;
}
- spin_lock_irqsave(&dev->dev_slock, flags);
+ mutex_lock(&dev->dev_mutex);
if (!(dev->vc_resource || dev->vp_resource)) {
pr_err("VCAP Err: %s: VC or VP res not acquired",
__func__);
- spin_unlock_irqrestore(&dev->dev_slock, flags);
+ mutex_unlock(&dev->dev_mutex);
return -EBUSY;
}
dev->vc_resource = 0;
dev->vp_resource = 0;
- spin_unlock_irqrestore(&dev->dev_slock, flags);
+ mutex_unlock(&dev->dev_mutex);
rc = streamoff_validate_q(&c_data->vc_vidq);
if (rc < 0)
return rc;
@@ -1562,10 +1570,11 @@
struct vcap_dev *dev = video_drvdata(file);
struct vcap_client_data *c_data;
struct vb2_queue *q;
- unsigned long flags;
int ret;
- c_data = kzalloc(sizeof(*c_data), GFP_KERNEL);
if (!dev)
+ return -EINVAL;
+ c_data = kzalloc(sizeof(*c_data), GFP_KERNEL);
+ if (!c_data)
return -ENOMEM;
c_data->dev = dev;
@@ -1619,22 +1628,33 @@
v4l2_fh_init(&c_data->vfh, dev->vfd);
v4l2_fh_add(&c_data->vfh);
- spin_lock_irqsave(&dev->dev_slock, flags);
+ mutex_lock(&dev->dev_mutex);
atomic_inc(&dev->open_clients);
ret = atomic_read(&dev->open_clients);
- spin_unlock_irqrestore(&dev->dev_slock, flags);
if (ret == 1) {
ret = vcap_enable(dev, dev->ddev, 54860000);
if (ret < 0) {
pr_err("Err: %s: Power on vcap failed", __func__);
+ mutex_unlock(&dev->dev_mutex);
+ goto vcap_power_failed;
+ }
+
+ ret = vp_dummy_event(c_data);
+ if (ret < 0) {
+ pr_err("Err: %s: Dummy Event failed", __func__);
+ mutex_unlock(&dev->dev_mutex);
+ vcap_disable(dev);
goto vcap_power_failed;
}
}
+ mutex_unlock(&dev->dev_mutex);
file->private_data = &c_data->vfh;
return 0;
vcap_power_failed:
+ atomic_dec(&dev->open_clients);
+
v4l2_fh_del(&c_data->vfh);
v4l2_fh_exit(&c_data->vfh);
vb2_queue_release(&c_data->vp_out_vidq);
@@ -1651,7 +1671,6 @@
{
struct vcap_dev *dev = video_drvdata(file);
struct vcap_client_data *c_data = to_client_data(file->private_data);
- unsigned long flags;
int ret;
if (c_data == NULL)
@@ -1660,12 +1679,14 @@
if (c_data->streaming)
streamoff_work(c_data);
- spin_lock_irqsave(&dev->dev_slock, flags);
+ mutex_lock(&dev->dev_mutex);
atomic_dec(&dev->open_clients);
ret = atomic_read(&dev->open_clients);
- spin_unlock_irqrestore(&dev->dev_slock, flags);
- if (ret == 0)
+ mutex_unlock(&dev->dev_mutex);
+ if (ret == 0) {
vcap_disable(dev);
+ dev->vp_dummy_complete = false;
+ }
v4l2_fh_del(&c_data->vfh);
v4l2_fh_exit(&c_data->vfh);
vb2_queue_release(&c_data->vp_out_vidq);
@@ -1908,7 +1929,8 @@
atomic_set(&dev->vp_enabled, 0);
atomic_set(&dev->open_clients, 0);
dev->ddev = &pdev->dev;
- spin_lock_init(&dev->dev_slock);
+ mutex_init(&dev->dev_mutex);
+ init_waitqueue_head(&dev->vp_dummy_waitq);
vcap_disable(dev);
dprintk(1, "Exit probe succesfully");
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index be1b4ff..b73185d 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -261,6 +261,12 @@
int rc;
irq = readl_relaxed(VCAP_VP_INT_STATUS);
+ if (dev->vp_dummy_event == true) {
+ writel_relaxed(irq, VCAP_VP_INT_CLEAR);
+ dev->vp_dummy_complete = true;
+ wake_up(&dev->vp_dummy_waitq);
+ return IRQ_HANDLED;
+ }
if (irq & 0x02000000) {
v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
@@ -434,6 +440,8 @@
return -ENOEXEC;
}
buf = &c_data->vid_vp_action.bufNR;
+ if (!buf)
+ return -ENOMEM;
frame_size = c_data->vp_in_fmt.width * c_data->vp_in_fmt.height;
if (c_data->vp_in_fmt.pixfmt == V4L2_PIX_FMT_NV16)
@@ -442,7 +450,7 @@
tot_size = frame_size / 2 * 3;
buf->vaddr = kzalloc(tot_size, GFP_KERNEL);
- if (!buf)
+ if (!buf->vaddr)
return -ENOMEM;
buf->paddr = virt_to_phys(buf->vaddr);
@@ -478,6 +486,74 @@
return;
}
+int vp_dummy_event(struct vcap_client_data *c_data)
+{
+ struct vcap_dev *dev = c_data->dev;
+ unsigned int width, height;
+ unsigned long paddr;
+ void *temp;
+ uint32_t reg;
+ int rc = 0;
+
+ dprintk(2, "%s: Start VP dummy event\n", __func__);
+ temp = kzalloc(0x1200, GFP_KERNEL);
+ if (!temp) {
+ pr_err("%s: Failed to alloc mem", __func__);
+ return -ENOMEM;
+ }
+ paddr = virt_to_phys(temp);
+
+ width = c_data->vp_out_fmt.width;
+ height = c_data->vp_out_fmt.height;
+
+ c_data->vp_out_fmt.width = 0x3F;
+ c_data->vp_out_fmt.height = 0x16;
+
+ config_vp_format(c_data);
+ writel_relaxed(paddr, VCAP_VP_T1_Y_BASE_ADDR);
+ writel_relaxed(paddr + 0x2C0, VCAP_VP_T1_C_BASE_ADDR);
+ writel_relaxed(paddr + 0x440, VCAP_VP_T2_Y_BASE_ADDR);
+ writel_relaxed(paddr + 0x700, VCAP_VP_T2_C_BASE_ADDR);
+ writel_relaxed(paddr + 0x880, VCAP_VP_OUT_Y_BASE_ADDR);
+ writel_relaxed(paddr + 0xB40, VCAP_VP_OUT_C_BASE_ADDR);
+ writel_iowmb(paddr + 0x1100, VCAP_VP_MOTION_EST_ADDR);
+ writel_relaxed(4 << 20 | 0x2 << 4, VCAP_VP_IN_CONFIG);
+ writel_relaxed(4 << 20 | 0x1 << 4, VCAP_VP_OUT_CONFIG);
+
+ dev->vp_dummy_event = true;
+
+ writel_relaxed(0x01100101, VCAP_VP_INTERRUPT_ENABLE);
+ writel_iowmb(0x00000000, VCAP_VP_CTRL);
+ writel_iowmb(0x00030000, VCAP_VP_CTRL);
+
+ enable_irq(dev->vpirq->start);
+ rc = wait_event_interruptible_timeout(dev->vp_dummy_waitq,
+ dev->vp_dummy_complete, msecs_to_jiffies(50));
+ if (!rc && !dev->vp_dummy_complete) {
+ pr_err("%s: VP dummy event timeout", __func__);
+ rc = -ETIME;
+ writel_iowmb(0x00000000, VCAP_VP_CTRL);
+
+ writel_iowmb(0x00000001, VCAP_VP_SW_RESET);
+ writel_iowmb(0x00000000, VCAP_VP_SW_RESET);
+ dev->vp_dummy_complete = false;
+ }
+
+ writel_relaxed(0x00000000, VCAP_VP_INTERRUPT_ENABLE);
+ disable_irq(dev->vpirq->start);
+ dev->vp_dummy_event = false;
+
+ reg = readl_relaxed(VCAP_OFFSET(0x0D94));
+ writel_relaxed(reg, VCAP_OFFSET(0x0D9C));
+
+ c_data->vp_out_fmt.width = width;
+ c_data->vp_out_fmt.height = height;
+ kfree(temp);
+
+ dprintk(2, "%s: Exit VP dummy event\n", __func__);
+ return rc;
+}
+
int kickoff_vp(struct vcap_client_data *c_data)
{
struct vcap_dev *dev;
diff --git a/drivers/media/video/vcap_vp.h b/drivers/media/video/vcap_vp.h
index 5415e54..5c32903 100644
--- a/drivers/media/video/vcap_vp.h
+++ b/drivers/media/video/vcap_vp.h
@@ -100,5 +100,6 @@
void deinit_nr_buf(struct vcap_client_data *c_data);
int kickoff_vp(struct vcap_client_data *c_data);
int continue_vp(struct vcap_client_data *c_data);
+int vp_dummy_event(struct vcap_client_data *c_data);
#endif
diff --git a/drivers/mfd/pm8821-irq.c b/drivers/mfd/pm8821-irq.c
index 2dcc792..ff68c08 100644
--- a/drivers/mfd/pm8821-irq.c
+++ b/drivers/mfd/pm8821-irq.c
@@ -22,6 +22,7 @@
#include <linux/mfd/pm8xxx/pm8821-irq.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <mach/mpm.h>
#define PM8821_TOTAL_IRQ_MASTERS 2
#define PM8821_BLOCKS_PER_MASTER 7
@@ -31,7 +32,7 @@
#define PM8821_IRQ_MASK_REG_OFFSET 0x08
#define SSBI_REG_ADDR_IRQ_MASTER0 0x30
#define SSBI_REG_ADDR_IRQ_MASTER1 0xB0
-
+#define MPM_PIN_FOR_8821_IRQ 7
#define SSBI_REG_ADDR_IRQ_IT_STATUS(master_base, block) (master_base + block)
/*
@@ -410,8 +411,12 @@
devirq, rc);
kfree(chip);
return ERR_PTR(rc);
- } else
+ } else{
irq_set_irq_wake(devirq, 1);
+ msm_mpm_set_pin_wake(MPM_PIN_FOR_8821_IRQ, 1);
+ msm_mpm_set_pin_type(MPM_PIN_FOR_8821_IRQ,
+ pdata->irq_trigger_flag);
+ }
}
return chip;
diff --git a/drivers/mfd/pm8xxx-spk.c b/drivers/mfd/pm8xxx-spk.c
index 297ddfa..2de70f4 100644
--- a/drivers/mfd/pm8xxx-spk.c
+++ b/drivers/mfd/pm8xxx-spk.c
@@ -162,7 +162,10 @@
val = pm8xxx_spk_read(PM8XXX_SPK_CTL1_REG_OFF);
if (val < 0)
return val;
- val |= (enable << 3);
+ if (enable)
+ val |= (1 << 3);
+ else
+ val &= ~(1 << 3);
ret = pm8xxx_spk_write(PM8XXX_SPK_CTL1_REG_OFF, val);
if (!ret)
ret = pm8xxx_spk_bank_write(addr, 6, PWM_EN_MASK);
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index d833707..08f5ab9 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -20,6 +20,7 @@
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
@@ -2092,7 +2093,14 @@
if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
if (is_auto_prog_done(host)) {
- if (!mrq->stop)
+ /*
+ * Auto-prog done will be enabled for following cases:
+ * mrq->sbc | mrq->stop
+ * _____________|________________
+ * True | Don't care
+ * False | False (CMD24, ACMD25 use case)
+ */
+ if (mrq->sbc || !mrq->stop)
host->curr.wait_for_auto_prog_done = true;
} else {
if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
@@ -2529,6 +2537,12 @@
curr = host->plat->pin_data->gpio_data;
for (i = 0; i < curr->size; i++) {
+ if (!gpio_is_valid(curr->gpio[i].no)) {
+ rc = -EINVAL;
+ pr_err("%s: Invalid gpio = %d\n",
+ mmc_hostname(host->mmc), curr->gpio[i].no);
+ goto free_gpios;
+ }
if (enable) {
if (curr->gpio[i].is_always_on &&
curr->gpio[i].is_enabled)
@@ -2553,7 +2567,7 @@
goto out;
free_gpios:
- for (; i >= 0; i--) {
+ for (i--; i >= 0; i--) {
gpio_free(curr->gpio[i].no);
curr->gpio[i].is_enabled = false;
}
@@ -4778,6 +4792,298 @@
spin_unlock_irqrestore(&host->lock, flags);
}
+/*
+ * msmsdcc_dt_get_array - Wrapper fn to read an array of 32 bit integers
+ *
+ * @dev: device node from which the property value is to be read.
+ * @prop_name: name of the property to be searched.
+ * @out_array: filled array returned to caller
+ * @len: filled array size returned to caller
+ * @size: expected size of the array
+ *
+ * If expected "size" doesn't match with "len" an error is returned. If
+ * expected size is zero, the length of actual array is returned provided
+ * return value is zero.
+ *
+ * RETURNS:
+ * zero on success, negative error if failed.
+ */
+static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
+ u32 **out_array, int *len, int size)
+{
+ int ret = 0;
+ u32 *array = NULL;
+ struct device_node *np = dev->of_node;
+
+ if (of_get_property(np, prop_name, len)) {
+ size_t sz;
+ sz = *len = *len / sizeof(*array);
+
+ if (sz > 0 && !(size > 0 && (sz != size))) {
+ array = devm_kzalloc(dev, sz * sizeof(*array),
+ GFP_KERNEL);
+ if (!array) {
+ dev_err(dev, "%s: no memory\n", prop_name);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = of_property_read_u32_array(np, prop_name,
+ array, sz);
+ if (ret < 0) {
+ dev_err(dev, "%s: error reading array %d\n",
+ prop_name, ret);
+ goto out;
+ }
+ } else {
+ dev_err(dev, "%s invalid size\n", prop_name);
+ ret = -EINVAL;
+ goto out;
+ }
+ } else {
+ dev_err(dev, "%s not specified\n", prop_name);
+ ret = -EINVAL;
+ goto out;
+ }
+ *out_array = array;
+out:
+ if (ret)
+ *len = 0;
+ return ret;
+}
+
+static int msmsdcc_dt_get_pad_pull_info(struct device *dev, int id,
+ struct msm_mmc_pad_pull_data **pad_pull_data)
+{
+ int ret = 0, base = 0, len, i;
+ u32 *tmp;
+ struct msm_mmc_pad_pull_data *pull_data;
+ struct msm_mmc_pad_pull *pull;
+
+ switch (id) {
+ case 1:
+ base = TLMM_PULL_SDC1_CLK;
+ break;
+ case 2:
+ base = TLMM_PULL_SDC2_CLK;
+ break;
+ case 3:
+ base = TLMM_PULL_SDC3_CLK;
+ break;
+ case 4:
+ base = TLMM_PULL_SDC4_CLK;
+ break;
+ default:
+ dev_err(dev, "%s: Invalid slot id\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ pull_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_pull_data),
+ GFP_KERNEL);
+ if (!pull_data) {
+ dev_err(dev, "No memory msm_mmc_pad_pull_data\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ pull_data->size = 3; /* array size for clk, cmd, data */
+
+ /* Allocate on, off configs for clk, cmd, data */
+ pull = devm_kzalloc(dev, 2 * pull_data->size *\
+ sizeof(struct msm_mmc_pad_pull), GFP_KERNEL);
+ if (!pull) {
+ dev_err(dev, "No memory for msm_mmc_pad_pull\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ pull_data->on = pull;
+ pull_data->off = pull + pull_data->size;
+
+ ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-on",
+ &tmp, &len, pull_data->size);
+ if (!ret) {
+ for (i = 0; i < len; i++) {
+ pull_data->on[i].no = base + i;
+ pull_data->on[i].val = tmp[i];
+ dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
+ i, pull_data->on[i].val);
+ }
+ } else {
+ goto err;
+ }
+
+ ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-off",
+ &tmp, &len, pull_data->size);
+ if (!ret) {
+ for (i = 0; i < len; i++) {
+ pull_data->off[i].no = base + i;
+ pull_data->off[i].val = tmp[i];
+ dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
+ i, pull_data->off[i].val);
+ }
+ } else {
+ goto err;
+ }
+
+ *pad_pull_data = pull_data;
+err:
+ return ret;
+}
+
+static int msmsdcc_dt_get_pad_drv_info(struct device *dev, int id,
+ struct msm_mmc_pad_drv_data **pad_drv_data)
+{
+ int ret = 0, base = 0, len, i;
+ u32 *tmp;
+ struct msm_mmc_pad_drv_data *drv_data;
+ struct msm_mmc_pad_drv *drv;
+
+ switch (id) {
+ case 1:
+ base = TLMM_HDRV_SDC1_CLK;
+ break;
+ case 2:
+ base = TLMM_HDRV_SDC2_CLK;
+ break;
+ case 3:
+ base = TLMM_HDRV_SDC3_CLK;
+ break;
+ case 4:
+ base = TLMM_HDRV_SDC4_CLK;
+ break;
+ default:
+ dev_err(dev, "%s: Invalid slot id\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ drv_data = devm_kzalloc(dev, sizeof(struct msm_mmc_pad_drv_data),
+ GFP_KERNEL);
+ if (!drv_data) {
+ dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ drv_data->size = 3; /* array size for clk, cmd, data */
+
+ /* Allocate on, off configs for clk, cmd, data */
+ drv = devm_kzalloc(dev, 2 * drv_data->size *\
+ sizeof(struct msm_mmc_pad_drv), GFP_KERNEL);
+ if (!drv) {
+ dev_err(dev, "No memory msm_mmc_pad_drv\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ drv_data->on = drv;
+ drv_data->off = drv + drv_data->size;
+
+ ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-on",
+ &tmp, &len, drv_data->size);
+ if (!ret) {
+ for (i = 0; i < len; i++) {
+ drv_data->on[i].no = base + i;
+ drv_data->on[i].val = tmp[i];
+ dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
+ i, drv_data->on[i].val);
+ }
+ } else {
+ goto err;
+ }
+
+ ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-off",
+ &tmp, &len, drv_data->size);
+ if (!ret) {
+ for (i = 0; i < len; i++) {
+ drv_data->off[i].no = base + i;
+ drv_data->off[i].val = tmp[i];
+ dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
+ i, drv_data->off[i].val);
+ }
+ } else {
+ goto err;
+ }
+
+ *pad_drv_data = drv_data;
+err:
+ return ret;
+}
+
+static int msmsdcc_dt_parse_gpio_info(struct device *dev,
+ struct mmc_platform_data *pdata)
+{
+ int ret = 0, id = 0, cnt, i;
+ struct msm_mmc_pin_data *pin_data;
+ struct device_node *np = dev->of_node;
+
+ pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
+ if (!pin_data) {
+ dev_err(dev, "No memory for pin_data\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ cnt = of_gpio_count(np);
+ if (cnt > 0) {
+ pin_data->is_gpio = true;
+
+ pin_data->gpio_data = devm_kzalloc(dev,
+ sizeof(struct msm_mmc_gpio_data), GFP_KERNEL);
+ if (!pin_data->gpio_data) {
+ dev_err(dev, "No memory for gpio_data\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ pin_data->gpio_data->size = cnt;
+ pin_data->gpio_data->gpio = devm_kzalloc(dev,
+ cnt * sizeof(struct msm_mmc_gpio), GFP_KERNEL);
+ if (!pin_data->gpio_data->gpio) {
+ dev_err(dev, "No memory for gpio\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0; i < cnt; i++) {
+ const char *name = NULL;
+ char result[32];
+ pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
+ of_property_read_string_index(np,
+ "qcom,sdcc-gpio-names", i, &name);
+
+ snprintf(result, 32, "%s-%s",
+ dev_name(dev), name ? name : "?");
+ pin_data->gpio_data->gpio[i].name = result;
+ dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
+ pin_data->gpio_data->gpio[i].name,
+ pin_data->gpio_data->gpio[i].no);
+ }
+ } else {
+ pin_data->pad_data = devm_kzalloc(dev,
+ sizeof(struct msm_mmc_pad_data), GFP_KERNEL);
+ if (!pin_data->pad_data) {
+ dev_err(dev, "No memory for pin_data->pad_data\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ of_property_read_u32(np, "cell-index", &id);
+
+ ret = msmsdcc_dt_get_pad_pull_info(dev, id,
+ &pin_data->pad_data->pull);
+ if (ret)
+ goto err;
+ ret = msmsdcc_dt_get_pad_drv_info(dev, id,
+ &pin_data->pad_data->drv);
+ if (ret)
+ goto err;
+ }
+
+ pdata->pin_data = pin_data;
+err:
+ if (ret)
+ dev_err(dev, "%s failed with err %d\n", __func__, ret);
+ return ret;
+}
+
#define MAX_PROP_SIZE 32
static int msmsdcc_dt_parse_vreg_info(struct device *dev,
struct msm_mmc_reg_data **vreg_data, const char *vreg_name)
@@ -4867,29 +5173,10 @@
pdata->mmc_bus_width = 0;
}
- if (of_get_property(np, "qcom,sdcc-sup-voltages", &sup_volt_len)) {
- size_t sz;
- sz = sup_volt_len / sizeof(*sup_voltages);
- if (sz > 0) {
- sup_voltages = devm_kzalloc(dev,
- sz * sizeof(*sup_voltages), GFP_KERNEL);
- if (!sup_voltages) {
- dev_err(dev, "No memory for supported voltage\n");
- goto err;
- }
-
- ret = of_property_read_u32_array(np,
- "qcom,sdcc-sup-voltages", sup_voltages, sz);
- if (ret < 0) {
- dev_err(dev, "error while reading voltage"
- "ranges %d\n", ret);
- goto err;
- }
- } else {
- dev_err(dev, "No supported voltages\n");
- goto err;
- }
- for (i = 0; i < sz; i += 2) {
+ ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-sup-voltages",
+ &sup_voltages, &sup_volt_len, 0);
+ if (!ret) {
+ for (i = 0; i < sup_volt_len; i += 2) {
u32 mask;
mask = mmc_vddrange_to_ocrmask(sup_voltages[i],
@@ -4899,37 +5186,13 @@
pdata->ocr_mask |= mask;
}
dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
- } else {
- dev_err(dev, "Supported voltage range not specified\n");
}
- if (of_get_property(np, "qcom,sdcc-clk-rates", &clk_table_len)) {
- size_t sz;
- sz = clk_table_len / sizeof(*clk_table);
-
- if (sz > 0) {
- clk_table = devm_kzalloc(dev, sz * sizeof(*clk_table),
- GFP_KERNEL);
- if (!clk_table) {
- dev_err(dev, "No memory for clock table\n");
- goto err;
- }
-
- ret = of_property_read_u32_array(np,
- "qcom,sdcc-clk-rates", clk_table, sz);
- if (ret < 0) {
- dev_err(dev, "error while reading clk"
- "table %d\n", ret);
- goto err;
- }
- } else {
- dev_err(dev, "clk_table not specified\n");
- goto err;
- }
+ ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-clk-rates",
+ &clk_table, &clk_table_len, 0);
+ if (!ret) {
pdata->sup_clk_table = clk_table;
- pdata->sup_clk_cnt = sz;
- } else {
- dev_err(dev, "Supported clock rates not specified\n");
+ pdata->sup_clk_cnt = clk_table_len;
}
pdata->vreg_data = devm_kzalloc(dev,
@@ -4947,6 +5210,9 @@
&pdata->vreg_data->vdd_io_data, "vdd-io"))
goto err;
+ if (msmsdcc_dt_parse_gpio_info(dev, pdata))
+ goto err;
+
len = of_property_count_strings(np, "qcom,sdcc-bus-speed-mode");
for (i = 0; i < len; i++) {
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index 36414e0..8cef99e 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -2778,6 +2778,9 @@
}
if (slc->def > 0)
slc->def--;
+ /* Disconnect source port to free it up */
+ if (SLIM_HDL_TO_LA(slc->srch) == sb->laddr)
+ slc->srch = 0;
if (slc->def == 0)
ret = add_pending_ch(&sb->mark_removal, chan);
if (ret)
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 083ed19..1904706 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -174,7 +174,7 @@
#define UARTDM_TX_BUF_SIZE UART_XMIT_SIZE
#define UARTDM_RX_BUF_SIZE 512
#define RETRY_TIMEOUT 5
-#define UARTDM_NR 2
+#define UARTDM_NR 5
static struct dentry *debug_base;
static struct msm_hs_port q_uart_port[UARTDM_NR];
diff --git a/drivers/video/msm/external_common.c b/drivers/video/msm/external_common.c
index 36c8749..9f301fe 100644
--- a/drivers/video/msm/external_common.c
+++ b/drivers/video/msm/external_common.c
@@ -1858,6 +1858,9 @@
/* EDID_BLOCK_SIZE[0x80] Each page size in the EDID ROM */
uint8 edid_buf[0x80 * 4];
+ external_common_state->pt_scan_info = 0;
+ external_common_state->it_scan_info = 0;
+ external_common_state->ce_scan_info = 0;
external_common_state->preferred_video_format = 0;
external_common_state->present_3d = 0;
memset(&external_common_state->disp_mode_list, 0,
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index d045e69..703d65d 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -2558,17 +2558,19 @@
struct msm_fb_data_type *mfd, uint32 perf_level)
{
u32 clk_rate = mfd->panel_info.clk_rate;
- u32 pull_mode = 0, use_blt = 0;
+ u32 blt_chq_req = 0, use_blt = 0;
- if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
+ if ((mfd->panel_info.type == MIPI_VIDEO_PANEL) ||
+ (mfd->panel_info.type == MIPI_CMD_PANEL))
clk_rate = (&mfd->panel_info.mipi)->dsi_pclk_rate;
if ((mfd->panel_info.type == LCDC_PANEL) ||
(mfd->panel_info.type == MIPI_VIDEO_PANEL) ||
- (mfd->panel_info.type == DTV_PANEL))
- pull_mode = 1;
+ (mfd->panel_info.type == DTV_PANEL) ||
+ (mfd->panel_info.type == MIPI_CMD_PANEL))
+ blt_chq_req = 1;
- if (pull_mode && (req->src_rect.h > req->dst_rect.h ||
+ if (blt_chq_req && (req->src_rect.h > req->dst_rect.h ||
req->src_rect.w > req->dst_rect.w)) {
if (mdp4_overlay_validate_downscale(req, mfd, perf_level,
clk_rate))
@@ -2798,10 +2800,15 @@
mdp4_mixer_stage_down(pipe);
if (pipe->mixer_num == MDP4_MIXER0) {
+ mfd->use_ov0_blt &= ~(1 << (pipe->pipe_ndx-1));
+ mdp4_overlay_update_blt_mode(mfd);
#ifdef CONFIG_FB_MSM_MIPI_DSI
if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
- if (mfd->panel_power_on)
+ if (mfd->panel_power_on) {
mdp4_dsi_cmd_overlay_restore();
+ mdp4_dsi_cmd_dma_busy_wait(mfd);
+ mdp4_dsi_blt_dmap_busy_wait(mfd);
+ }
} else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
pipe->flags &= ~MDP_OV_PLAY_NOWAIT;
if (mfd->panel_power_on)
@@ -2810,8 +2817,11 @@
}
#else
if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
- if (mfd->panel_power_on)
+ if (mfd->panel_power_on) {
mdp4_mddi_overlay_restore();
+ mdp4_mddi_dma_busy_wait(mfd);
+ mdp4_mddi_blt_dmap_busy_wait(mfd);
+ }
}
#endif
else if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
@@ -2819,8 +2829,6 @@
if (mfd->panel_power_on)
mdp4_overlay_lcdc_vsync_push(mfd, pipe);
}
- mfd->use_ov0_blt &= ~(1 << (pipe->pipe_ndx-1));
- mdp4_overlay_update_blt_mode(mfd);
if (!mfd->use_ov0_blt)
mdp4_free_writeback_buf(mfd, MDP4_MIXER0);
} else { /* mixer1, DTV, ATV */
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index b90812f..b9d6037 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -698,11 +698,7 @@
struct mdp4_overlay_pipe *pipe;
if (!mfd->panel_power_on)
return;
- if (!dtv_pipe) {
- pr_debug("%s: no mixer1 base layer pipe allocated!\n",
- __func__);
- return;
- }
+
mutex_lock(&mfd->dma->ov_mutex);
if (dtv_pipe == NULL) {
if (mdp4_overlay_dtv_set(mfd, NULL)) {
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 36cbbbd..176f56b 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -642,6 +642,12 @@
struct msm_fb_panel_data *pdata = NULL;
int ret = 0;
+ if (hdmi_prim_display) {
+ MSM_FB_INFO("%s: hdmi primary handles early suspend only\n",
+ __func__);
+ return 0;
+ }
+
if ((!mfd) || (mfd->key != MFD_KEY))
return 0;
@@ -667,6 +673,12 @@
struct msm_fb_panel_data *pdata = NULL;
int ret = 0;
+ if (hdmi_prim_display) {
+ MSM_FB_INFO("%s: hdmi primary handles early resume only\n",
+ __func__);
+ return 0;
+ }
+
if ((!mfd) || (mfd->key != MFD_KEY))
return 0;
@@ -691,7 +703,8 @@
.runtime_suspend = msm_fb_runtime_suspend,
.runtime_resume = msm_fb_runtime_resume,
.runtime_idle = msm_fb_runtime_idle,
-#if (defined(CONFIG_SUSPEND) && defined(CONFIG_FB_MSM_HDMI_MSM_PANEL))
+#if (defined(CONFIG_SUSPEND) && defined(CONFIG_FB_MSM_HDMI_MSM_PANEL) && \
+ !defined(CONFIG_FB_MSM_HDMI_AS_PRIMARY))
.suspend = msm_fb_ext_suspend,
.resume = msm_fb_ext_resume,
#endif
@@ -725,7 +738,9 @@
static void msmfb_early_suspend(struct early_suspend *h)
{
struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
- early_suspend);
+ early_suspend);
+ struct msm_fb_panel_data *pdata = NULL;
+
#if defined(CONFIG_FB_MSM_MDP303)
/*
* For MDP with overlay, set framebuffer with black pixels
@@ -743,12 +758,37 @@
}
#endif
msm_fb_suspend_sub(mfd);
+
+ pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
+ if (hdmi_prim_display &&
+ (mfd->panel_info.type == HDMI_PANEL ||
+ mfd->panel_info.type == DTV_PANEL)) {
+ /* Turn off the HPD circuitry */
+ if (pdata->power_ctrl) {
+ MSM_FB_INFO("%s: Turning off HPD circuitry\n",
+ __func__);
+ pdata->power_ctrl(FALSE);
+ }
+ }
}
static void msmfb_early_resume(struct early_suspend *h)
{
struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
- early_suspend);
+ early_suspend);
+ struct msm_fb_panel_data *pdata = NULL;
+
+ pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
+ if (hdmi_prim_display &&
+ (mfd->panel_info.type == HDMI_PANEL ||
+ mfd->panel_info.type == DTV_PANEL)) {
+ /* Turn on the HPD circuitry */
+ if (pdata->power_ctrl) {
+ MSM_FB_INFO("%s: Turning on HPD circuitry\n", __func__);
+ pdata->power_ctrl(TRUE);
+ }
+ }
+
msm_fb_resume_sub(mfd);
}
#endif
@@ -1435,7 +1475,7 @@
ret = 0;
#ifdef CONFIG_HAS_EARLYSUSPEND
- if (mfd->panel_info.type != DTV_PANEL) {
+ if (hdmi_prim_display || mfd->panel_info.type != DTV_PANEL) {
mfd->early_suspend.suspend = msmfb_early_suspend;
mfd->early_suspend.resume = msmfb_early_resume;
mfd->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 2;
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 8aeadf6..6af2a3e 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -645,6 +645,11 @@
*(.security_initcall.init) \
VMLINUX_SYMBOL(__security_initcall_end) = .;
+#define COMPAT_EXPORTS \
+ VMLINUX_SYMBOL(__compat_exports_start) = .; \
+ *(.exportcompat.init) \
+ VMLINUX_SYMBOL(__compat_exports_end) = .;
+
#ifdef CONFIG_BLK_DEV_INITRD
#define INIT_RAM_FS \
. = ALIGN(4); \
diff --git a/include/linux/input/lis3dh.h b/include/linux/input/lis3dh.h
new file mode 100644
index 0000000..f081b06
--- /dev/null
+++ b/include/linux/input/lis3dh.h
@@ -0,0 +1,85 @@
+
+/******************** (C) COPYRIGHT 2010 STMicroelectronics ********************
+*
+* File Name : lis3dh_misc.h
+* Authors : MH - C&I BU - Application Team
+* : Matteo Dameno (matteo.dameno@st.com)
+* : Carmine Iascone (carmine.iascone@st.com)
+* : Samuel Huo (samuel.huo@st.com)
+* Version : V 1.1.0
+* Date : 07/10/2012
+*
+********************************************************************************
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 as
+* published by the Free Software Foundation.
+*
+* THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
+* OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE
+* PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT.
+* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
+* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
+* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
+* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+*
+* THIS SOFTWARE IS SPECIFICALLY DESIGNED FOR EXCLUSIVE USE WITH ST PARTS.
+*
+*******************************************************************************/
+
+#ifndef __LIS3DH_H__
+#define __LIS3DH_H__
+
+
+#define SAD0L 0x00
+#define SAD0H 0x01
+#define LIS3DH_ACC_I2C_SADROOT 0x0C
+#define LIS3DH_ACC_I2C_SAD_L ((LIS3DH_ACC_I2C_SADROOT<<1)|SAD0L)
+#define LIS3DH_ACC_I2C_SAD_H ((LIS3DH_ACC_I2C_SADROOT<<1)|SAD0H)
+#define LIS3DH_ACC_DEV_NAME "lis3dh_acc"
+
+
+/************************************************/
+/* Accelerometer defines section */
+/************************************************/
+
+/* Accelerometer Sensor Full Scale */
+#define LIS3DH_ACC_FS_MASK 0x30
+#define LIS3DH_ACC_G_2G 0x00
+#define LIS3DH_ACC_G_4G 0x10
+#define LIS3DH_ACC_G_8G 0x20
+#define LIS3DH_ACC_G_16G 0x30
+
+
+#ifdef __KERNEL__
+struct lis3dh_acc_platform_data {
+ int poll_interval;
+ int min_interval;
+
+ u8 g_range;
+
+ u8 axis_map_x;
+ u8 axis_map_y;
+ u8 axis_map_z;
+
+ u8 negate_x;
+ u8 negate_y;
+ u8 negate_z;
+
+ int (*init)(void);
+ void (*exit)(void);
+ int (*power_on)(void);
+ int (*power_off)(void);
+
+ /* set gpio_int[1,2] either to the choosen gpio pin number or to -EINVAL
+ * if leaved unconnected
+ */
+ int gpio_int1;
+ int gpio_int2;
+};
+#endif /* __KERNEL__ */
+
+#endif /* __LIS3DH_H__ */
+
+
+
diff --git a/include/media/vcap_v4l2.h b/include/media/vcap_v4l2.h
index f7d1e6b..9719aa6 100644
--- a/include/media/vcap_v4l2.h
+++ b/include/media/vcap_v4l2.h
@@ -158,10 +158,13 @@
atomic_t vc_enabled;
atomic_t vp_enabled;
- spinlock_t dev_slock;
+ struct mutex dev_mutex;
atomic_t open_clients;
bool vc_resource;
bool vp_resource;
+ bool vp_dummy_event;
+ bool vp_dummy_complete;
+ wait_queue_head_t vp_dummy_waitq;
struct workqueue_struct *vcap_wq;
struct vp_work_t vp_work;
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index eb89f4b..3526e29 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1334,6 +1334,15 @@
__u8 data[0];
} __packed;
+#define HCI_EV_LE_CONN_UPDATE_COMPLETE 0x03
+struct hci_ev_le_conn_update_complete {
+ __u8 status;
+ __le16 handle;
+ __le16 interval;
+ __le16 latency;
+ __le16 supervision_timeout;
+} __packed;
+
#define HCI_EV_LE_LTK_REQ 0x05
struct hci_ev_le_ltk_req {
__le16 handle;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 47b856c..22428c1 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1033,6 +1033,8 @@
int mgmt_connectable(u16 index, u8 connectable);
int mgmt_new_key(u16 index, struct link_key *key, u8 bonded);
int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le);
+int mgmt_le_conn_params(u16 index, bdaddr_t *bdaddr, u16 interval,
+ u16 latency, u16 timeout);
int mgmt_disconnected(u16 index, bdaddr_t *bdaddr);
int mgmt_disconnect_failed(u16 index);
int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index e34c425..3048339 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -379,3 +379,11 @@
bdaddr_t bdaddr;
__s8 rssi;
} __packed;
+
+#define MGMT_EV_LE_CONN_PARAMS 0xF000
+struct mgmt_ev_le_conn_params {
+ bdaddr_t bdaddr;
+ __u16 interval;
+ __u16 latency;
+ __u16 timeout;
+} __packed;
diff --git a/lib/spinlock_debug.c b/lib/spinlock_debug.c
index c1906e4..d0ec4f3 100644
--- a/lib/spinlock_debug.c
+++ b/lib/spinlock_debug.c
@@ -118,10 +118,6 @@
/* lockup suspected: */
if (print_once) {
print_once = 0;
- printk(KERN_EMERG "BUG: spinlock lockup on CPU#%d, "
- "%s/%d, %ps\n",
- raw_smp_processor_id(), current->comm,
- task_pid_nr(current), lock);
spin_dump(lock, "lockup");
#ifdef CONFIG_SMP
trigger_all_cpu_backtrace();
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index eb5a0cc..f83c108 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3191,6 +3191,10 @@
conn->state = BT_CONNECTED;
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
mgmt_connected(hdev->id, &ev->bdaddr, 1);
+ mgmt_le_conn_params(hdev->id, &ev->bdaddr,
+ __le16_to_cpu(ev->interval),
+ __le16_to_cpu(ev->latency),
+ __le16_to_cpu(ev->supervision_timeout));
hci_conn_hold(conn);
hci_conn_hold_device(conn);
@@ -3202,6 +3206,37 @@
hci_dev_unlock(hdev);
}
+static inline void hci_le_conn_update_complete_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_ev_le_conn_update_complete *ev = (void *) skb->data;
+ struct hci_conn *conn;
+
+ BT_DBG("%s status %d", hdev->name, ev->status);
+
+ hci_dev_lock(hdev);
+
+ conn = hci_conn_hash_lookup_handle(hdev,
+ __le16_to_cpu(ev->handle));
+ if (conn == NULL) {
+ BT_ERR("Unknown connection update");
+ goto unlock;
+ }
+
+ if (ev->status) {
+ BT_ERR("Connection update unsuccessful");
+ goto unlock;
+ }
+
+ mgmt_le_conn_params(hdev->id, &conn->dst,
+ __le16_to_cpu(ev->interval),
+ __le16_to_cpu(ev->latency),
+ __le16_to_cpu(ev->supervision_timeout));
+
+unlock:
+ hci_dev_unlock(hdev);
+}
+
static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
@@ -3271,6 +3306,10 @@
hci_le_conn_complete_evt(hdev, skb);
break;
+ case HCI_EV_LE_CONN_UPDATE_COMPLETE:
+ hci_le_conn_update_complete_evt(hdev, skb);
+ break;
+
case HCI_EV_LE_LTK_REQ:
hci_le_ltk_request_evt(hdev, skb);
break;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index dce8491..72234c1 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2633,6 +2633,20 @@
return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
}
+int mgmt_le_conn_params(u16 index, bdaddr_t *bdaddr, u16 interval,
+ u16 latency, u16 timeout)
+{
+ struct mgmt_ev_le_conn_params ev;
+
+ bacpy(&ev.bdaddr, bdaddr);
+ ev.interval = interval;
+ ev.latency = latency;
+ ev.timeout = timeout;
+
+ return mgmt_event(MGMT_EV_LE_CONN_PARAMS, index, &ev, sizeof(ev),
+ NULL);
+}
+
static void disconnect_rsp(struct pending_cmd *cmd, void *data)
{
struct mgmt_cp_disconnect *cp = cmd->param;
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 6bbb34b..276ff71 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -711,10 +711,6 @@
invalid_key:
hcon->sec_req = FALSE;
- /* Switch to Pairing Connection Parameters */
- hci_le_conn_update(hcon, SMP_MIN_CONN_INTERVAL, SMP_MAX_CONN_INTERVAL,
- SMP_MAX_CONN_LATENCY, SMP_SUPERVISION_TIMEOUT);
-
skb_pull(skb, sizeof(*rp));
memset(&cp, 0, sizeof(cp));
@@ -776,11 +772,6 @@
if (hcon->link_mode & HCI_LM_MASTER) {
struct smp_cmd_pairing cp;
- /* Switch to Pairing Connection Parameters */
- hci_le_conn_update(hcon, SMP_MIN_CONN_INTERVAL,
- SMP_MAX_CONN_INTERVAL, SMP_MAX_CONN_LATENCY,
- SMP_SUPERVISION_TIMEOUT);
-
build_pairing_cmd(conn, &cp, NULL, authreq);
hcon->preq[0] = SMP_CMD_PAIRING_REQ;
memcpy(&hcon->preq[1], &cp, sizeof(cp));
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 70d9fa9..bbf1b89 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -848,14 +848,14 @@
if (enable) {
sitar->adc_count++;
- snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS, 0xE0, 0xE0);
-
+ snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL,
+ 0x02, 0x02);
} else {
sitar->adc_count--;
if (!sitar->adc_count) {
if (!sitar->mbhc_polling_active)
- snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS,
- 0xE0, 0x0);
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_CLK_OTHR_CTL, 0xE0, 0x0);
}
}
}
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 3164a9b..68892c1 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -7312,14 +7312,13 @@
}
EXPORT_SYMBOL_GPL(tabla_hs_detect);
-static unsigned long slimbus_value;
-
static irqreturn_t tabla_slimbus_irq(int irq, void *data)
{
struct tabla_priv *priv = data;
struct snd_soc_codec *codec = priv->codec;
struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
int i, j, port_id, k, ch_mask_temp;
+ unsigned long slimbus_value;
u8 val;
for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
@@ -7352,7 +7351,8 @@
}
}
wcd9xxx_interface_reg_write(codec->control_data,
- TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
+ TABLA_SLIM_PGD_PORT_INT_CLR0 + i, slimbus_value);
+ val = 0x0;
}
return IRQ_HANDLED;
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index a0cad55..374e875 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -877,7 +877,7 @@
.name = "MSM8930 Media2",
.stream_name = "MultiMedia2",
.cpu_dai_name = "MultiMedia2",
- .platform_name = "msm-pcm-dsp",
+ .platform_name = "msm-multi-ch-pcm-dsp",
.dynamic = 1,
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index b110250..9c57161 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -678,6 +678,21 @@
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
},
{
+ .name = "MSM8974 Compr",
+ .stream_name = "COMPR",
+ .cpu_dai_name = "MultiMedia4",
+ .platform_name = "msm-compr-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
+ },
+ {
.name = "AUXPCM Hostless",
.stream_name = "AUXPCM Hostless",
.cpu_dai_name = "AUXPCM_HOSTLESS",
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index 1cf32aa..3791f24 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -2344,6 +2344,9 @@
/* send stop voice cmd */
voice_send_stop_voice_cmd(v);
+ /* Clear mute setting */
+ v->dev_tx.mute = common.default_mute_val;
+
/* detach VOCPROC and wait for response from mvm */
mvm_d_vocproc_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE),
@@ -3106,7 +3109,9 @@
v->dev_tx.mute = mute;
- if (v->voc_state == VOC_RUN)
+ if ((v->voc_state == VOC_RUN) ||
+ (v->voc_state == VOC_CHANGE) ||
+ (v->voc_state == VOC_STANDBY))
ret = voice_send_mute_cmd(v);
mutex_unlock(&v->lock);
@@ -3312,7 +3317,9 @@
v->dev_rx.volume = vol_idx;
- if (v->voc_state == VOC_RUN)
+ if ((v->voc_state == VOC_RUN) ||
+ (v->voc_state == VOC_CHANGE) ||
+ (v->voc_state == VOC_STANDBY))
ret = voice_send_vol_index_cmd(v);
mutex_unlock(&v->lock);
@@ -3501,6 +3508,15 @@
pr_err("setup voice failed\n");
goto fail;
}
+
+ ret = voice_send_vol_index_cmd(v);
+ if (ret < 0)
+ pr_err("voice volume failed\n");
+
+ ret = voice_send_mute_cmd(v);
+ if (ret < 0)
+ pr_err("voice mute failed\n");
+
ret = voice_send_start_voice_cmd(v);
if (ret < 0) {
pr_err("start voice failed\n");
@@ -3998,7 +4014,7 @@
memset((void *)common.cvs_cal.buf, 0, CVS_CAL_SIZE);
cont:
/* set default value */
- common.default_mute_val = 1; /* default is mute */
+ common.default_mute_val = 0; /* default is un-mute */
common.default_vol_val = 0;
common.default_sample_val = 8000;
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index 7723934..360744a 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -621,7 +621,11 @@
static __devinit int msm_compr_probe(struct platform_device *pdev)
{
- pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+ if (pdev->dev.of_node)
+ dev_set_name(&pdev->dev, "%s", "msm-compr-dsp");
+
+ dev_info(&pdev->dev, "%s: dev name %s\n",
+ __func__, dev_name(&pdev->dev));
return snd_soc_register_platform(&pdev->dev,
&msm_soc_platform);
}
@@ -632,10 +636,17 @@
return 0;
}
+static const struct of_device_id msm_compr_dt_match[] = {
+ {.compatible = "qcom,msm-compr-dsp"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, msm_compr_dt_match);
+
static struct platform_driver msm_compr_driver = {
.driver = {
.name = "msm-compr-dsp",
.owner = THIS_MODULE,
+ .of_match_table = msm_compr_dt_match,
},
.probe = msm_compr_probe,
.remove = __devexit_p(msm_compr_remove),
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 691ca21..aed6273 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -433,7 +433,7 @@
mmap_regions->hdr.dest_port = 0;
mmap_regions->hdr.token = 0;
mmap_regions->hdr.opcode = ADM_CMD_SHARED_MEM_MAP_REGIONS;
- mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_EBI_POOL & 0x00ff;
+ mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL & 0x00ff;
mmap_regions->num_regions = bufcnt & 0x00ff;
mmap_regions->property_flag = 0x00;
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 5b30e8e..4875a69 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -867,7 +867,7 @@
mregion->hdr.dest_port = 0;
mregion->hdr.token = 0;
mregion->hdr.opcode = AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS;
- mregion->mem_pool_id = ADSP_MEMORY_MAP_EBI_POOL;
+ mregion->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
mregion->num_regions = 1;
mregion->property_flag = 0x00;
/* Todo */
@@ -946,7 +946,7 @@
mregion->hdr.dest_port = 0;
mregion->hdr.token = 0;
mregion->hdr.opcode = AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS;
- mregion->mem_pool_id = ADSP_MEMORY_MAP_EBI_POOL;
+ mregion->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
mregion->num_regions = 1;
mregion->property_flag = 0x00;
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 0bb88e8..a3af263 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -2265,7 +2265,7 @@
q6asm_add_mmaphdr(ac, &mmap_regions->hdr, cmd_size,
TRUE, ((ac->session << 8) | dir));
mmap_regions->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
- mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_EBI_POOL;
+ mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
mmap_regions->num_regions = bufcnt & 0x00ff;
mmap_regions->property_flag = 0x00;
payload = ((u8 *) mmap_region_cmd +
@@ -2408,7 +2408,7 @@
mmap_regions, ((ac->session << 8) | dir));
mmap_regions->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
- mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_EBI_POOL;
+ mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
mmap_regions->num_regions = 1; /*bufcnt & 0x00ff; */
mmap_regions->property_flag = 0x00;
pr_debug("map_regions->nregions = %d\n", mmap_regions->num_regions);