Merge "ASoC: msm: Support send flush to DSP Multichannel PCM playback"
diff --git a/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt b/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
index 068e256..5f18893 100644
--- a/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
+++ b/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
@@ -40,3 +40,21 @@
EXPORT_COMPAT("qcom,a-driver") to the driver, similar to EXPORT_SYMBOL.
The EXPORT_COMPAT is to ensure that memory is only carved out if the
driver is actually enabled, otherwise the memory will not be used.
+
+In order to specify the size and address of the fixed memory which has
+previously been removed the memory-fixed binding can be used. This assumes
+that the region has been removed by a separate memblock-remove property
+present in the device tree.
+
+Required parameters:
+-qcom,memory-fixed: base and size of the fixed memory region
+
+ qcom,a-driver {
+ compatible = "qcom,a-driver";
+ /* Fixed Memory region of 4MB at 0x200000*/
+ qcom,memory-fixed = <0x200000 0x400000>;
+ };
+
+This region is assumed to be a part of a separate hole that has been removed
+and this binding specifies the fixed location and size of the region within
+that hole.
diff --git a/Documentation/devicetree/bindings/fb/mdss-edp.txt b/Documentation/devicetree/bindings/fb/mdss-edp.txt
index 4fedc72..3c4e1d3 100644
--- a/Documentation/devicetree/bindings/fb/mdss-edp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-edp.txt
@@ -4,15 +4,20 @@
VESA EDP display interface specification.
Required properties
-- compatible : Must be "qcom,mdss-edp".
-- reg : Offset and length of the register set for the device.
-- reg-names : Names to refer to register sets related to this device
-- vdda-supply : Phandle for vdd regulator device node.
-- gpio-panel-en : GPIO for supplying power to panel and to backlight driver.
-- status : A string that has to be set to "okay/ok" to enable
- the driver. By default this property will be set to
- "disable". Will be set to "ok/okay" status for specific
- platforms.
+- compatible : Must be "qcom,mdss-edp".
+- reg : Offset and length of the register set for the
+ device.
+- reg-names : Names to refer to register sets related to this
+ device
+- vdda-supply : Phandle for vdd regulator device node.
+- gpio-panel-en : GPIO for supplying power to panel and backlight
+ driver.
+- qcom,panel-lpg-channel : LPG channel for backlight.
+- qcom,panel-pwm-period : PWM period in microseconds.
+- status : A string that has to be set to "okay/ok" to enable
+ the driver. By default this property will be set to
+ "disable". Will be set to "ok/okay" status for
+ specific platforms.
Example:
mdss_edp: qcom,mdss_edp@fd923400 {
@@ -22,6 +27,8 @@
reg-names = "edp_base", "mmss_cc_base";
vdda-supply = <&pm8941_l12>;
gpio-panel-en = <&msmgpio 58 0>;
+ qcom,panel-lpg-channel = <7>; /* LPG Channel 8 */
+ qcom,panel-pwm-period = <53>;
status = "disable";
};
diff --git a/Documentation/devicetree/bindings/hwmon/epm_adc.txt b/Documentation/devicetree/bindings/hwmon/epm_adc.txt
index 89edc16..a0ca490 100644
--- a/Documentation/devicetree/bindings/hwmon/epm_adc.txt
+++ b/Documentation/devicetree/bindings/hwmon/epm_adc.txt
@@ -9,7 +9,7 @@
EPM node
Required properties:
-- compatible : should be "qcom,epm-adc" for EPM using PSoC5.
+- compatible : should be "cy,epm-adc-cy8c5568lti-114" for EPM using PSoC5.
- reg : chip select for the device.
- interrupt-parent : should be phandle of the interrupt controller
servicing the interrupt for this device.
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index 51bf9e6..eda7cba 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -12,14 +12,14 @@
- compatible : should be "qcom,leds-qpnp"
Each LED module is represented as a node of "leds-qpnp". This
-node will furthur contain the type of LED supported and its
+node will further contain the type of LED supported and its
properties.
Required properties:
- qcom,id : must be one of values supported in enum qpnp_led
-- qcom,label : type of led that will be used, ie "wled"
+- label : type of led that will be used, ie "wled"
- qcom,max-current : maximum current that the LED can sustain
-= qcom,name : name the led will be called by in sysfs entry
+- linux,name : name of the led that is used in led framework
WLED is primarily used as display backlight. Display subsystem uses
LED triggers for WLED to control the brightness as needed.
@@ -41,17 +41,22 @@
qcom,leds@d800 {
compatible = "qcom,leds-qpnp";
- reg = <0xD800 0x100>;
- linux,default-trigger = "bkl-trigger"
- qcom,label = "wled";
- qcom,cs-out-en;
- qcom,op-fdbck;
- qcom,default-state "off";
- qcom,max-current = <25>;
- qcom,ctrl-delay-us = <0>;
- qcom,boost-curr-lim = <3>;
- qcom,cp-sel = <0>;
- qcom,switch-freq = <2>;
- qcom,ovp-val = <2>;
- qcom,num-strings = <1>;
- }
+ status = "okay";
+ qcom,wled_0 {
+ linux,default-trigger = "bkl-trigger"
+ label = "wled";
+ qcom,cs-out-en;
+ qcom,op-fdbck;
+ qcom,default-state "off";
+ qcom,max-current = <25>;
+ qcom,ctrl-delay-us = <0>;
+ qcom,boost-curr-lim = <3>;
+ qcom,cp-sel = <0>;
+ qcom,switch-freq = <2>;
+ qcom,ovp-val = <2>;
+ qcom,num-strings = <1>;
+ qcom,id = <0>;
+ linux,name = "led:wled_backlight";
+ };
+ };
+
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 41ffd8a..dd59ae8 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -10,8 +10,7 @@
- reg: Pairs of physical base addresses and region sizes of
memory mapped registers.
- reg-names: Names of the bases for the above registers. "qdsp6_base",
- "halt_base", "rmb_base", "restart_reg" and "clamp_reg"
- are expected.
+ "halt_base", "rmb_base", and "restart_reg" are expected.
- vdd_mss-supply: Reference to the regulator that supplies the processor.
- qcom,firmware-name: Base name of the firmware image. Ex. "mdsp"
- qcom,pil-self-auth: <0> if the hardware does not require self-authenticating
@@ -24,10 +23,9 @@
reg = <0xfc880000 0x100>,
<0xfd485000 0x400>,
<0xfc820000 0x020>,
- <0xfc401680 0x004>,
- <0xfc980008 0x004>;
+ <0xfc401680 0x004>;
reg-names = "qdsp6_base", "halt_base", "rmb_base",
- "restart_reg", "clamp_reg";
+ "restart_reg";
vdd_mss-supply = <&pm8841_s3>;
qcom,firmware-name = "mba";
diff --git a/Documentation/devicetree/bindings/power/bq28400-battery.txt b/Documentation/devicetree/bindings/power/bq28400-battery.txt
new file mode 100644
index 0000000..3879b4d
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/bq28400-battery.txt
@@ -0,0 +1,18 @@
+TI BQ28400 Battery Gas Gauge
+
+The bq28400 monitors the battery temperature, capacity, voltage, current etc.
+The device interface is I2C, its I2C slave 7-bit address is 0xb.
+The device is usually embedded inside the "smart battery" pack.
+
+node required properties:
+- compatible: Must be "ti,bq28400-battery".
+- reg: I2C Address must be 0xb.
+
+Example:
+ i2c@f9967000 {
+ battery@b {
+ compatible = "ti,bq28400-battery";
+ reg = <0xb>;
+ };
+ };
+
diff --git a/Documentation/devicetree/bindings/power/smb350.txt b/Documentation/devicetree/bindings/power/smb350.txt
new file mode 100644
index 0000000..6f21236
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/smb350.txt
@@ -0,0 +1,43 @@
+Summit smb350 battery charger
+
+The smb350 charger supports stack-cell battery charging.
+
+The smb350 interface is via I2C bus.
+The i2c slave 7-bit address is programmable at manufacture.
+
+Node required properties:
+- compatible: Must be "summit,smb350-charger".
+- reg: The device 7-bit I2C address.
+- summit,stat-gpio gpio which smb350 STAT pin connects to.
+- summit,chg-en-n-gpio gpio which control charging enable.
+- summit,chg-susp-n-gpio gpio which control device shutdown
+- summit,chg-current-ma charging current in milliamps.
+- summit,term-current-ma charging termination current in milliamps.
+ valid values are 200/300/400/500/600/700.
+ A value of zero means no termination current.
+
+Example:
+ i2c@f9967000 {
+ cell-index = <0>;
+ compatible = "qcom,i2c-qup";
+ reg = <0Xf9967000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ interrupts = <0 105 0>;
+ interrupt-names = "qup_err_intr";
+ qcom,i2c-bus-freq = <100000>;
+ qcom,i2c-src-freq = <24000000>;
+ label = "blsp_11";
+
+ smb350-charger@2b {
+ compatible = "summit,smb350-charger";
+ reg = <0x2b>; /* 0x56/0x57 */
+ summit,stat-gpio = <&pm8941_gpios 30 0x00>;
+ summit,chg-en-n-gpio = <&pm8941_gpios 10 0x00>;
+ summit,chg-susp-n-gpio = <&pm8941_gpios 13 0x00>;
+ summit,chg-current-ma = <1600>;
+ summit,term-current-ma = <200>;
+ };
+ };
+
diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
index 9cc9e6e..99274d5 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -11,7 +11,7 @@
"otg_irq" : Interrupt for DWC3 core's OTG Events
- <supply-name>-supply: phandle to the regulator device tree node
Required "supply-name" examples are "SSUSB_VDDCX", "SSUSB_1p8",
- "HSUSB_VDDCX", "HSUSB_1p8", "HSUSB_3p3".
+ "HSUSB_VDDCX", "HSUSB_1p8", "HSUSB_3p3" and "vbus_dwc3".
- qcom,dwc-usb3-msm-dbm-eps: Number of endpoints avaliable for
the DBM (Device Bus Manager). The DBM is HW unit which is part of
the MSM USB3.0 core (which also includes the Synopsys DesignWare
@@ -25,19 +25,25 @@
- qcom,msm_bus,active_only
- qcom,msm_bus,num_paths
- qcom,msm_bus,vectors
+- interrupt-names : Optional interrupt resource entries are:
+ "hs_phy_irq" : Interrupt from HSPHY for asynchronous events in LPM.
+ This is not used if wakeup events are received externally (e.g. PMIC)
+- qcom,dwc-usb3-msm-otg-capability: If present then depends on PMIC
+ for VBUS notifications, otherwise depends on PHY.
Example MSM USB3.0 controller device node :
usb@f9200000 {
compatible = "qcom,dwc-usb3-msm";
reg = <0xF9200000 0xFA000>,
<0xFD4AB000 0x4>;
- interrupts = <0 131 0 0 179 0>;
- interrupt-names = "irq", "otg_irq";
+ interrupts = <0 131 0>, <0 179 0>, <0 133 0>;
+ interrupt-names = "irq", "otg_irq", "hs_phy_irq";
SSUSB_VDDCX-supply = <&pm8841_s2>;
SSUSB_1p8-supply = <&pm8941_l6>;
HSUSB_VDDCX-supply = <&pm8841_s2>;
HSUSB_1p8-supply = <&pm8941_l6>;
HSUSB_3p3-supply = <&pm8941_l24>;
+ vbus_dwc3-supply = <&pm8941_mvs1>;
qcom,dwc-usb3-msm-dbm-eps = <4>
qcom,msm_bus,name = "usb3";
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 1d95407..de30884 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -996,61 +996,61 @@
qcom,leds@d800 {
compatible = "qcom,leds-qpnp";
reg = <0xd800 0x100>;
- qcom,label = "wled";
+ label = "wled";
};
qcom,leds@d900 {
compatible = "qcom,leds-qpnp";
reg = <0xd900 0x100>;
- qcom,label = "wled";
+ label = "wled";
};
qcom,leds@da00 {
compatible = "qcom,leds-qpnp";
reg = <0xda00 0x100>;
- qcom,label = "wled";
+ label = "wled";
};
qcom,leds@db00 {
compatible = "qcom,leds-qpnp";
reg = <0xdb00 0x100>;
- qcom,label = "wled";
+ label = "wled";
};
qcom,leds@dc00 {
compatible = "qcom,leds-qpnp";
reg = <0xdc00 0x100>;
- qcom,label = "wled";
+ label = "wled";
};
qcom,leds@dd00 {
compatible = "qcom,leds-qpnp";
reg = <0xdd00 0x100>;
- qcom,label = "wled";
+ label = "wled";
};
qcom,leds@de00 {
compatible = "qcom,leds-qpnp";
reg = <0xde00 0x100>;
- qcom,label = "wled";
+ label = "wled";
};
qcom,leds@df00 {
compatible = "qcom,leds-qpnp";
reg = <0xdf00 0x100>;
- qcom,label = "wled";
+ label = "wled";
};
qcom,leds@e000 {
compatible = "qcom,leds-qpnp";
reg = <0xe000 0x100>;
- qcom,label = "wled";
+ label = "wled";
};
qcom,leds@e100 {
compatible = "qcom,leds-qpnp";
reg = <0xe100 0x100>;
- qcom,label = "wled";
+ label = "wled";
};
pwm@b100 {
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
new file mode 100644
index 0000000..8fe94a5
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -0,0 +1,274 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+ /* Stub Regulators */
+
+ / {
+ pm8026_s1: regulator-s1 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_s1";
+ qcom,hpm-min-load = <100000>;
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1150000>;
+ };
+
+ pm8026_s2: regulator-s2 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_s2";
+ qcom,hpm-min-load = <100000>;
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ };
+
+ pm8026_s3: regulator-s3 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_s3";
+ qcom,hpm-min-load = <100000>;
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ };
+
+ pm8026_s4: regulator-s4 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_s4";
+ qcom,hpm-min-load = <100000>;
+ regulator-min-microvolt = <2100000>;
+ regulator-max-microvolt = <2100000>;
+ };
+
+ pm8026_s5: regulator-s5 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_s5";
+ qcom,hpm-min-load = <100000>;
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1150000>;
+ };
+
+ pm8026_l1: regulator-l1 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l1";
+ parent-supply = <&pm8026_s3>;
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ };
+
+ pm8026_l2: regulator-l2 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l2";
+ parent-supply = <&pm8026_s3>;
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pm8026_l3: regulator-l3 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l3";
+ parent-supply = <&pm8026_s3>;
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1150000>;
+ };
+
+ pm8026_l4: regulator-l4 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l4";
+ parent-supply = <&pm8026_s3>;
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pm8026_l5: regulator-l5 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l5";
+ parent-supply = <&pm8026_s3>;
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pm8026_l6: regulator-l6 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l6";
+ parent-supply = <&pm8026_s4>;
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8026_l7: regulator-l7 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l7";
+ parent-supply = <&pm8026_s4>;
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1850000>;
+ regulator-max-microvolt = <1850000>;
+ };
+
+ pm8026_l8: regulator-l8 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l8";
+ parent-supply = <&pm8026_s4>;
+ qcom,hpm-min-load = <5000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8026_l9: regulator-l9 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l9";
+ parent-supply = <&pm8026_s4>;
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ };
+
+ pm8026_l10: regulator-l10 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l10";
+ parent-supply = <&pm8026_s4>;
+ qcom,hpm-min-load = <5000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8026_l12: regulator-l12 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l12";
+ qcom,hpm-min-load = <5000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8026_l14: regulator-l14 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l14";
+ qcom,hpm-min-load = <5000>;
+ regulator-min-microvolt = <2750000>;
+ regulator-max-microvolt = <2750000>;
+ };
+
+ pm8026_l15: regulator-l15 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l15";
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
+
+ pm8026_l16: regulator-l16 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l16";
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ };
+
+ pm8026_l17: regulator-l17 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l17";
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8026_l18: regulator-l18 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l18";
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8026_l19: regulator-l19 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l19";
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ };
+
+ pm8026_l20: regulator-l20 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l20";
+ qcom,hpm-min-load = <5000>;
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+ };
+
+ pm8026_l21: regulator-l21 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l21";
+ qcom,hpm-min-load = <5000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8026_l22: regulator-l22 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l22";
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8026_l23: regulator-l23 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l23";
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8026_l24: regulator-l24 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l24";
+ parent-supply = <&pm8026_s3>;
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ };
+
+ pm8026_l26: regulator-l26 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l26";
+ parent-supply = <&pm8026_s3>;
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ };
+
+ pm8026_l27: regulator-l27 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l27";
+ parent-supply = <&pm8026_s4>;
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ };
+
+ pm8026_l28: regulator-l28 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l28";
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8026_lvs1: regulator-lvs1 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_lvs1";
+ parent-supply = <&pm8026_l6>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 6d2ffec..db2bfb3 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -58,6 +58,9 @@
reg = <0xf9a55000 0x400>;
interrupts = <0 134 0>;
interrupt-names = "core_irq";
+ HSUSB_VDDCX-supply = <&pm8026_s1>;
+ HSUSB_1p8-supply = <&pm8026_l10>;
+ HSUSB_3p3-supply = <&pm8026_l20>;
qcom,hsusb-otg-phy-type = <2>;
qcom,hsusb-otg-mode = <1>;
@@ -70,3 +73,5 @@
};
};
+
+/include/ "msm8226-regulator.dtsi"
diff --git a/arch/arm/boot/dts/msm8910-regulator.dtsi b/arch/arm/boot/dts/msm8910-regulator.dtsi
new file mode 100644
index 0000000..a32d4ab
--- /dev/null
+++ b/arch/arm/boot/dts/msm8910-regulator.dtsi
@@ -0,0 +1,218 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+ /* Stub Regulators */
+
+ / {
+ pm8110_s1: regulator-s1 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_s1";
+ qcom,hpm-min-load = <100000>;
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1150000>;
+ };
+
+ pm8110_s2: regulator-s2 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_s2";
+ qcom,hpm-min-load = <100000>;
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ };
+
+ pm8110_s3: regulator-s3 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_s3";
+ qcom,hpm-min-load = <100000>;
+ regulator-min-microvolt = <1350000>;
+ regulator-max-microvolt = <1350000>;
+ };
+
+ pm8110_s4: regulator-s4 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_s4";
+ qcom,hpm-min-load = <100000>;
+ regulator-min-microvolt = <2150000>;
+ regulator-max-microvolt = <2150000>;
+ };
+
+ pm8110_l1: regulator-l1 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_l1";
+ parent-supply = <&pm8110_s3>;
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ };
+
+ pm8110_l2: regulator-l2 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_l2";
+ parent-supply = <&pm8110_s3>;
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pm8110_l3: regulator-l3 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_l3";
+ parent-supply = <&pm8110_s3>;
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1150000>;
+ };
+
+ pm8110_l4: regulator-l4 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_l4";
+ parent-supply = <&pm8110_s3>;
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pm8110_l5: regulator-l5 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_l5";
+ parent-supply = <&pm8110_s3>;
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ };
+
+ pm8110_l6: regulator-l6 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_l6";
+ parent-supply = <&pm8110_s4>;
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8110_l7: regulator-l7 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_l7";
+ parent-supply = <&pm8110_s4>;
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ };
+
+ pm8110_l8: regulator-l8 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_l8";
+ parent-supply = <&pm8110_s4>;
+ qcom,hpm-min-load = <5000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8110_l9: regulator-l9 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_l9";
+ parent-supply = <&pm8110_s4>;
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ };
+
+ pm8110_l10: regulator-l10 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_l10";
+ parent-supply = <&pm8110_s4>;
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8110_l12: regulator-l12 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_l12";
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ pm8110_l14: regulator-l14 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_l14";
+ parent-supply = <&pm8110_s4>;
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8110_l15: regulator-l15 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_l15";
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ pm8110_l16: regulator-l16 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_l16";
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ };
+
+ pm8110_l17: regulator-l17 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_l17";
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <2900000>;
+ regulator-max-microvolt = <2900000>;
+ };
+
+ pm8110_l18: regulator-l18 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_l18";
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8110_l19: regulator-l19 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_l19";
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ };
+
+ pm8110_l20: regulator-l20 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_l20";
+ qcom,hpm-min-load = <5000>;
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+ };
+
+ pm8110_l21: regulator-l21 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_l21";
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8110_l22: regulator-l22 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8110_l22";
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8910.dtsi b/arch/arm/boot/dts/msm8910.dtsi
index 83dabfb..a2e1338 100644
--- a/arch/arm/boot/dts/msm8910.dtsi
+++ b/arch/arm/boot/dts/msm8910.dtsi
@@ -62,4 +62,47 @@
compatible = "qcom,android-usb";
};
+ sdcc1: qcom,sdcc@f9824000 {
+ cell-index = <1>; /* SDC1 eMMC slot */
+ compatible = "qcom,msm-sdcc";
+ reg = <0xf9824000 0x800>;
+ reg-names = "core_mem";
+ interrupts = <0 123 0>;
+ interrupt-names = "core_irq";
+
+ 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>;
+ qcom,sdcc-nonremovable;
+ qcom,sdcc-bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+ };
+
+ sdcc2: qcom,sdcc@f98a4000 {
+ cell-index = <2>; /* SDC2 SD card slot */
+ compatible = "qcom,msm-sdcc";
+ reg = <0xf98a4000 0x800>;
+ reg-names = "core_mem";
+ interrupts = <0 125 0>;
+ interrupt-names = "core_irq";
+
+ 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>;
+ qcom,sdcc-xpc;
+ qcom,sdcc-bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+ qcom,sdcc-current-limit = <800>;
+ };
+
};
+
+/include/ "msm8910-regulator.dtsi"
diff --git a/arch/arm/boot/dts/msm8974-cdp.dts b/arch/arm/boot/dts/msm8974-cdp.dts
index 0e0f6cf..b8b3141 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-cdp.dts
@@ -13,356 +13,10 @@
/dts-v1/;
/include/ "msm8974.dtsi"
-/include/ "dsi-panel-toshiba-720p-video.dtsi"
+/include/ "msm8974-cdp.dtsi"
/ {
model = "Qualcomm MSM 8974 CDP";
compatible = "qcom,msm8974-cdp", "qcom,msm8974";
qcom,msm-id = <126 1 0>;
-
- serial@f991e000 {
- status = "ok";
- };
-
- qcom,mdss_dsi@fd922800 {
- qcom,mdss_dsi_toshiba_720p_video {
- status = "ok";
- };
- };
-
- qcom,hdmi_tx@fd922100 {
- status = "ok";
- };
-
- i2c@f9924000 {
- atmel_mxt_ts@4a {
- compatible = "atmel,mxt-ts";
- reg = <0x4a>;
- interrupt-parent = <&msmgpio>;
- interrupts = <61 0x2>;
- vdd_ana-supply = <&pm8941_l18>;
- vcc_i2c-supply = <&pm8941_lvs1>;
- atmel,reset-gpio = <&msmgpio 60 0x00>;
- atmel,irq-gpio = <&msmgpio 61 0x00>;
- atmel,panel-coords = <0 0 760 1424>;
- atmel,display-coords = <0 0 720 1280>;
- atmel,i2c-pull-up = <1>;
- atmel,cfg_1 {
- atmel,family-id = <0x82>;
- atmel,variant-id = <0x19>;
- atmel,version = <0x10>;
- atmel,build = <0xaa>;
- atmel,config = [
- /* Object 6, Instance = 0 */
- 00 00 00 00 00 00
- /* Object 38, Instance = 0 */
- 15 00 02 10 08 0C 00 00
- /* Object 7, Instance = 0 */
- FF FF 32 03
- /* Object 8, Instance = 0 */
- 0F 00 0A 0A 00 00 0A 00 00 00
- /* Object 9, Instance = 0 */
- 83 00 00 18 0E 00 70 32 02 01
- 00 03 01 01 05 0A 0A 0A 90 05
- F8 02 00 00 0F 0F 00 00 48 2D
- 07 0C 00 00 00 00
- /* Object 15, Instance = 0 */
- 00 00 00 00 00 00 00 00 00 00
- 00
- /* Object 18, Instance = 0 */
- 00 00
- /* Object 19, Instance = 0 */
- 00 00 00 00 00 00
- /* Object 23, Instance = 0 */
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00 00
- /* Object 25, Instance = 0 */
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00 00
- /* Object 40, Instance = 0 */
- 00 00 00 00 00
- /* Object 42, Instance = 0 */
- 00 00 00 00 00 00 00 00 00 00
- /* Object 46, Instance = 0 */
- 00 00 10 10 00 00 03 00 00 01
- /* Object 47, Instance = 0 */
- 08 0A 28 0A 02 0A 00 8C 00 20
- 00 00 00
- /* Object 55, Instance = 0 */
- 00 00 00 00 00 00
- /* Object 56, Instance = 0 */
- 03 00 01 18 05 05 05 05 05 05
- 05 05 05 05 05 05 05 05 05 05
- 05 05 05 05 05 05 05 05 00 00
- 00 00 00 00 00 00 00 00 00 00
- 00 00
- /* Object 57, Instance = 0 */
- 00 00 00
- /* Object 61, Instance = 0 */
- 00 00 00 00 00
- /* Object 61, Instance = 1 */
- 00 00 00 00 00
- /* Object 62, Instance = 0 */
- 7F 03 00 16 00 00 00 00 00 00
- 04 08 10 18 05 00 0A 05 05 50
- 14 19 34 1A 64 00 00 04 40 00
- 00 00 00 00 30 32 02 00 01 00
- 05 00 00 00 00 00 00 00 00 00
- 00 00 0C 00
- ];
- };
- };
- };
-
- gpio_keys {
- compatible = "gpio-keys";
- input-name = "gpio-keys";
-
- camera_snapshot {
- label = "camera_snapshot";
- gpios = <&pm8941_gpios 3 0x1>;
- linux,input-type = <1>;
- linux,code = <0x2fe>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
-
- camera_focus {
- label = "camera_focus";
- gpios = <&pm8941_gpios 4 0x1>;
- linux,input-type = <1>;
- linux,code = <0x210>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
-
- vol_up {
- label = "volume_up";
- gpios = <&pm8941_gpios 5 0x1>;
- linux,input-type = <1>;
- linux,code = <115>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
- };
-
- spi@f9923000 {
- ethernet-switch@2 {
- compatible = "micrel,ks8851";
- reg = <2>;
- interrupt-parent = <&msmgpio>;
- interrupts = <94 0>;
- spi-max-frequency = <4800000>;
- rst-gpio = <&pm8941_mpps 6 0>;
- vdd-io-supply = <&spi_eth_vreg>;
- vdd-phy-supply = <&spi_eth_vreg>;
- };
- };
-};
-
-&sdcc2 {
- #address-cells = <0>;
- interrupt-parent = <&sdcc2>;
- interrupts = <0 1 2>;
- #interrupt-cells = <1>;
- interrupt-map-mask = <0xffffffff>;
- interrupt-map = <0 &intc 0 125 0
- 1 &intc 0 220 0
- 2 &msmgpio 62 0x3>;
- interrupt-names = "core_irq", "bam_irq", "status_irq";
- cd-gpios = <&msmgpio 62 0x1>;
- wp-gpios = <&pm8941_gpios 29 0x1>;
-};
-
-&pm8941_gpios {
- gpio@c000 { /* GPIO 1 */
- };
-
- gpio@c100 { /* GPIO 2 */
- };
-
- gpio@c200 { /* GPIO 3 */
- qcom,mode = <0>;
- qcom,pull = <0>;
- qcom,vin-sel = <2>;
- qcom,select = <0>;
- };
-
- gpio@c300 { /* GPIO 4 */
- qcom,mode = <0>;
- qcom,pull = <0>;
- qcom,vin-sel = <2>;
- qcom,select = <0>;
- };
-
- gpio@c400 { /* GPIO 5 */
- qcom,mode = <0>;
- qcom,pull = <0>;
- qcom,vin-sel = <2>;
- qcom,select = <0>;
- };
-
- gpio@c500 { /* GPIO 6 */
- };
-
- gpio@c600 { /* GPIO 7 */
- };
-
- gpio@c700 { /* GPIO 8 */
- };
-
- gpio@c800 { /* GPIO 9 */
- };
-
- gpio@c900 { /* GPIO 10 */
- };
-
- gpio@ca00 { /* GPIO 11 */
- };
-
- gpio@cb00 { /* GPIO 12 */
- };
-
- gpio@cc00 { /* GPIO 13 */
- };
-
- gpio@cd00 { /* GPIO 14 */
- };
-
- gpio@ce00 { /* GPIO 15 */
- qcom,mode = <1>;
- qcom,output-type = <0>;
- qcom,pull = <5>;
- qcom,vin-sel = <2>;
- qcom,out-strength = <3>;
- qcom,src-select = <2>;
- qcom,master-en = <1>;
- };
-
- gpio@cf00 { /* GPIO 16 */
- };
-
- gpio@d000 { /* GPIO 17 */
- };
-
- gpio@d100 { /* GPIO 18 */
- };
-
- gpio@d200 { /* GPIO 19 */
- qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
- qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
- qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
- qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
- qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
- qcom,src-select = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
- qcom,master-en = <1>;
- };
-
- gpio@d300 { /* GPIO 20 */
- };
-
- gpio@d400 { /* GPIO 21 */
- };
-
- gpio@d500 { /* GPIO 22 */
- };
-
- gpio@d600 { /* GPIO 23 */
- };
-
- gpio@d700 { /* GPIO 24 */
- };
-
- gpio@d800 { /* GPIO 25 */
- };
-
- gpio@d900 { /* GPIO 26 */
- };
-
- gpio@da00 { /* GPIO 27 */
- };
-
- gpio@db00 { /* GPIO 28 */
- };
-
- gpio@dc00 { /* GPIO 29 */
- qcom,pull = <0>; /* set to default pull */
- qcom,master-en = <1>;
- qcom,vin-sel = <2>; /* select 1.8 V source */
- };
-
- gpio@dd00 { /* GPIO 30 */
- };
-
- gpio@de00 { /* GPIO 31 */
- };
-
- gpio@df00 { /* GPIO 32 */
- };
-
- gpio@e000 { /* GPIO 33 */
- };
-
- gpio@e100 { /* GPIO 34 */
- };
-
- gpio@e200 { /* GPIO 35 */
- };
-
- gpio@e300 { /* GPIO 36 */
- };
-};
-
-&pm8941_mpps {
-
- mpp@a000 { /* MPP 1 */
- };
-
- mpp@a100 { /* MPP 2 */
- };
-
- mpp@a200 { /* MPP 3 */
- };
-
- mpp@a300 { /* MPP 4 */
- };
-
- mpp@a400 { /* MPP 5 */
- /* SPI_ETH config */
- qcom,mode = <1>; /* DIG_OUT */
- qcom,output-type = <0>; /* CMOS */
- qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
- qcom,src-select = <0>; /* CONSTANT */
- qcom,master-en = <1>; /* ENABLE MPP */
- };
-
- mpp@a500 { /* MPP 6 */
- /* SPI_ETH_RST config */
- qcom,mode = <1>; /* DIG_OUT */
- qcom,output-type = <0>; /* CMOS */
- qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
- qcom,src-select = <0>; /* CONSTANT */
- qcom,master-en = <1>; /* ENABLE MPP */
- };
-
- mpp@a600 { /* MPP 7 */
- };
-
- mpp@a700 { /* MPP 8 */
- };
-};
-
-&pm8841_mpps {
-
- mpp@a000 { /* MPP 1 */
- };
-
- mpp@a100 { /* MPP 2 */
- };
-
- mpp@a200 { /* MPP 3 */
- };
-
- mpp@a300 { /* MPP 4 */
- };
};
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
new file mode 100644
index 0000000..00f20ad
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -0,0 +1,361 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "dsi-panel-toshiba-720p-video.dtsi"
+
+/ {
+ serial@f991e000 {
+ status = "ok";
+ };
+
+ qcom,mdss_dsi@fd922800 {
+ qcom,mdss_dsi_toshiba_720p_video {
+ status = "ok";
+ };
+ };
+
+ qcom,hdmi_tx@fd922100 {
+ status = "ok";
+ };
+
+ i2c@f9924000 {
+ atmel_mxt_ts@4a {
+ compatible = "atmel,mxt-ts";
+ reg = <0x4a>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <61 0x2>;
+ vdd_ana-supply = <&pm8941_l18>;
+ vcc_i2c-supply = <&pm8941_lvs1>;
+ atmel,reset-gpio = <&msmgpio 60 0x00>;
+ atmel,irq-gpio = <&msmgpio 61 0x00>;
+ atmel,panel-coords = <0 0 760 1424>;
+ atmel,display-coords = <0 0 720 1280>;
+ atmel,i2c-pull-up = <1>;
+ atmel,cfg_1 {
+ atmel,family-id = <0x82>;
+ atmel,variant-id = <0x19>;
+ atmel,version = <0x10>;
+ atmel,build = <0xaa>;
+ atmel,config = [
+ /* Object 6, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 38, Instance = 0 */
+ 15 00 02 10 08 0C 00 00
+ /* Object 7, Instance = 0 */
+ FF FF 32 03
+ /* Object 8, Instance = 0 */
+ 0F 00 0A 0A 00 00 0A 00 00 00
+ /* Object 9, Instance = 0 */
+ 83 00 00 18 0E 00 70 32 02 01
+ 00 03 01 01 05 0A 0A 0A 90 05
+ F8 02 00 00 0F 0F 00 00 48 2D
+ 07 0C 00 00 00 00
+ /* Object 15, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00
+ /* Object 18, Instance = 0 */
+ 00 00
+ /* Object 19, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 23, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00
+ /* Object 25, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00
+ /* Object 40, Instance = 0 */
+ 00 00 00 00 00
+ /* Object 42, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ /* Object 46, Instance = 0 */
+ 00 00 10 10 00 00 03 00 00 01
+ /* Object 47, Instance = 0 */
+ 08 0A 28 0A 02 0A 00 8C 00 20
+ 00 00 00
+ /* Object 55, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 56, Instance = 0 */
+ 03 00 01 18 05 05 05 05 05 05
+ 05 05 05 05 05 05 05 05 05 05
+ 05 05 05 05 05 05 05 05 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00
+ /* Object 57, Instance = 0 */
+ 00 00 00
+ /* Object 61, Instance = 0 */
+ 00 00 00 00 00
+ /* Object 61, Instance = 1 */
+ 00 00 00 00 00
+ /* Object 62, Instance = 0 */
+ 7F 03 00 16 00 00 00 00 00 00
+ 04 08 10 18 05 00 0A 05 05 50
+ 14 19 34 1A 64 00 00 04 40 00
+ 00 00 00 00 30 32 02 00 01 00
+ 05 00 00 00 00 00 00 00 00 00
+ 00 00 0C 00
+ ];
+ };
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&pm8941_gpios 3 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&pm8941_gpios 4 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&pm8941_gpios 5 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
+
+ spi@f9923000 {
+ ethernet-switch@2 {
+ compatible = "micrel,ks8851";
+ reg = <2>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <94 0>;
+ spi-max-frequency = <4800000>;
+ rst-gpio = <&pm8941_mpps 6 0>;
+ vdd-io-supply = <&spi_eth_vreg>;
+ vdd-phy-supply = <&spi_eth_vreg>;
+ };
+ };
+};
+
+&sdcc2 {
+ #address-cells = <0>;
+ interrupt-parent = <&sdcc2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 220 0
+ 2 &msmgpio 62 0x3>;
+ interrupt-names = "core_irq", "bam_irq", "status_irq";
+ cd-gpios = <&msmgpio 62 0x1>;
+ wp-gpios = <&pm8941_gpios 29 0x1>;
+};
+
+&pm8941_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+
+ gpio@c600 { /* GPIO 7 */
+ };
+
+ gpio@c700 { /* GPIO 8 */
+ };
+
+ gpio@c800 { /* GPIO 9 */
+ };
+
+ gpio@c900 { /* GPIO 10 */
+ };
+
+ gpio@ca00 { /* GPIO 11 */
+ };
+
+ gpio@cb00 { /* GPIO 12 */
+ };
+
+ gpio@cc00 { /* GPIO 13 */
+ };
+
+ gpio@cd00 { /* GPIO 14 */
+ };
+
+ gpio@ce00 { /* GPIO 15 */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <2>;
+ qcom,out-strength = <3>;
+ qcom,src-select = <2>;
+ qcom,master-en = <1>;
+ };
+
+ gpio@cf00 { /* GPIO 16 */
+ };
+
+ gpio@d000 { /* GPIO 17 */
+ };
+
+ gpio@d100 { /* GPIO 18 */
+ };
+
+ gpio@d200 { /* GPIO 19 */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
+ qcom,src-select = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
+ qcom,master-en = <1>;
+ };
+
+ gpio@d300 { /* GPIO 20 */
+ };
+
+ gpio@d400 { /* GPIO 21 */
+ };
+
+ gpio@d500 { /* GPIO 22 */
+ };
+
+ gpio@d600 { /* GPIO 23 */
+ };
+
+ gpio@d700 { /* GPIO 24 */
+ };
+
+ gpio@d800 { /* GPIO 25 */
+ };
+
+ gpio@d900 { /* GPIO 26 */
+ };
+
+ gpio@da00 { /* GPIO 27 */
+ };
+
+ gpio@db00 { /* GPIO 28 */
+ };
+
+ gpio@dc00 { /* GPIO 29 */
+ qcom,pull = <0>; /* set to default pull */
+ qcom,master-en = <1>;
+ qcom,vin-sel = <2>; /* select 1.8 V source */
+ };
+
+ gpio@dd00 { /* GPIO 30 */
+ };
+
+ gpio@de00 { /* GPIO 31 */
+ };
+
+ gpio@df00 { /* GPIO 32 */
+ };
+
+ gpio@e000 { /* GPIO 33 */
+ };
+
+ gpio@e100 { /* GPIO 34 */
+ };
+
+ gpio@e200 { /* GPIO 35 */
+ };
+
+ gpio@e300 { /* GPIO 36 */
+ };
+};
+
+&pm8941_mpps {
+
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ /* SPI_ETH config */
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+ qcom,src-select = <0>; /* CONSTANT */
+ qcom,master-en = <1>; /* ENABLE MPP */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ /* SPI_ETH_RST config */
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+ qcom,src-select = <0>; /* CONSTANT */
+ qcom,master-en = <1>; /* ENABLE MPP */
+ };
+
+ mpp@a600 { /* MPP 7 */
+ };
+
+ mpp@a700 { /* MPP 8 */
+ };
+};
+
+&pm8841_mpps {
+
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-fluid.dts b/arch/arm/boot/dts/msm8974-fluid.dts
index 891379f..b014e14 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dts
+++ b/arch/arm/boot/dts/msm8974-fluid.dts
@@ -13,359 +13,10 @@
/dts-v1/;
/include/ "msm8974.dtsi"
-/include/ "dsi-panel-toshiba-720p-video.dtsi"
+/include/ "msm8974-fluid.dtsi"
/ {
model = "Qualcomm MSM 8974 FLUID";
compatible = "qcom,msm8974-fluid", "qcom,msm8974";
qcom,msm-id = <126 3 0>;
-
- serial@f991e000 {
- status = "ok";
- };
-
- qcom,mdss_dsi@fd922800 {
- qcom,mdss_dsi_toshiba_720p_video {
- status = "ok";
- };
- };
-
- qcom,hdmi_tx@fd922100 {
- status = "ok";
- };
-
- i2c@f9924000 {
- atmel_mxt_ts@4a {
- compatible = "atmel,mxt-ts";
- reg = <0x4a>;
- interrupt-parent = <&msmgpio>;
- interrupts = <61 0x2>;
- vdd_ana-supply = <&pm8941_l18>;
- vcc_i2c-supply = <&pm8941_lvs1>;
- atmel,reset-gpio = <&msmgpio 60 0x00>;
- atmel,irq-gpio = <&msmgpio 61 0x00>;
- atmel,panel-coords = <0 0 760 1424>;
- atmel,display-coords = <0 0 720 1280>;
- atmel,i2c-pull-up = <1>;
- atmel,cfg_1 {
- atmel,family-id = <0x82>;
- atmel,variant-id = <0x19>;
- atmel,version = <0x10>;
- atmel,build = <0xaa>;
- atmel,config = [
- /* Object 6, Instance = 0 */
- 00 00 00 00 00 00
- /* Object 38, Instance = 0 */
- 15 00 02 10 08 0C 00 00
- /* Object 7, Instance = 0 */
- FF FF 32 03
- /* Object 8, Instance = 0 */
- 0F 00 0A 0A 00 00 0A 00 00 00
- /* Object 9, Instance = 0 */
- 83 00 00 18 0E 00 70 32 02 01
- 00 03 01 01 05 0A 0A 0A 90 05
- F8 02 00 00 0F 0F 00 00 48 2D
- 07 0C 00 00 00 00
- /* Object 15, Instance = 0 */
- 00 00 00 00 00 00 00 00 00 00
- 00
- /* Object 18, Instance = 0 */
- 00 00
- /* Object 19, Instance = 0 */
- 00 00 00 00 00 00
- /* Object 23, Instance = 0 */
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00 00
- /* Object 25, Instance = 0 */
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00 00
- /* Object 40, Instance = 0 */
- 00 00 00 00 00
- /* Object 42, Instance = 0 */
- 00 00 00 00 00 00 00 00 00 00
- /* Object 46, Instance = 0 */
- 00 00 10 10 00 00 03 00 00 01
- /* Object 47, Instance = 0 */
- 08 0A 28 0A 02 0A 00 8C 00 20
- 00 00 00
- /* Object 55, Instance = 0 */
- 00 00 00 00 00 00
- /* Object 56, Instance = 0 */
- 03 00 01 18 05 05 05 05 05 05
- 05 05 05 05 05 05 05 05 05 05
- 05 05 05 05 05 05 05 05 00 00
- 00 00 00 00 00 00 00 00 00 00
- 00 00
- /* Object 57, Instance = 0 */
- 00 00 00
- /* Object 61, Instance = 0 */
- 00 00 00 00 00
- /* Object 61, Instance = 1 */
- 00 00 00 00 00
- /* Object 62, Instance = 0 */
- 7F 03 00 16 00 00 00 00 00 00
- 04 08 10 18 05 00 0A 05 05 50
- 14 19 34 1A 64 00 00 04 40 00
- 00 00 00 00 30 32 02 00 01 00
- 05 00 00 00 00 00 00 00 00 00
- 00 00 0C 00
- ];
- };
- };
- };
-
- gpio_keys {
- compatible = "gpio-keys";
- input-name = "gpio-keys";
-
- camera_snapshot {
- label = "camera_snapshot";
- gpios = <&pm8941_gpios 3 0x1>;
- linux,input-type = <1>;
- linux,code = <0x2fe>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
-
- camera_focus {
- label = "camera_focus";
- gpios = <&pm8941_gpios 4 0x1>;
- linux,input-type = <1>;
- linux,code = <0x210>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
-
- vol_up {
- label = "volume_up";
- gpios = <&pm8941_gpios 5 0x1>;
- linux,input-type = <1>;
- linux,code = <115>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
- };
-
- spi@f9923000 {
- ethernet-switch@2 {
- compatible = "micrel,ks8851";
- reg = <2>;
- interrupt-parent = <&msmgpio>;
- interrupts = <94 0>;
- spi-max-frequency = <4800000>;
- rst-gpio = <&pm8941_mpps 6 0>;
- vdd-io-supply = <&spi_eth_vreg>;
- vdd-phy-supply = <&spi_eth_vreg>;
- };
- };
-};
-
-&sdcc1 {
- qcom,sdcc-bus-width = <4>;
-};
-
-&sdcc2 {
- #address-cells = <0>;
- interrupt-parent = <&sdcc2>;
- interrupts = <0 1 2>;
- #interrupt-cells = <1>;
- interrupt-map-mask = <0xffffffff>;
- interrupt-map = <0 &intc 0 125 0
- 1 &intc 0 220 0
- 2 &msmgpio 62 0x3>;
- interrupt-names = "core_irq", "bam_irq", "status_irq";
- cd-gpios = <&msmgpio 62 0x1>;
-};
-
-&pm8941_gpios {
- gpio@c000 { /* GPIO 1 */
- };
-
- gpio@c100 { /* GPIO 2 */
- };
-
- gpio@c200 { /* GPIO 3 */
- qcom,mode = <0>;
- qcom,pull = <0>;
- qcom,vin-sel = <2>;
- qcom,select = <0>;
- };
-
- gpio@c300 { /* GPIO 4 */
- qcom,mode = <0>;
- qcom,pull = <0>;
- qcom,vin-sel = <2>;
- qcom,select = <0>;
- };
-
- gpio@c400 { /* GPIO 5 */
- qcom,mode = <0>;
- qcom,pull = <0>;
- qcom,vin-sel = <2>;
- qcom,select = <0>;
- };
-
- gpio@c500 { /* GPIO 6 */
- };
-
- gpio@c600 { /* GPIO 7 */
- };
-
- gpio@c700 { /* GPIO 8 */
- };
-
- gpio@c800 { /* GPIO 9 */
- };
-
- gpio@c900 { /* GPIO 10 */
- };
-
- gpio@ca00 { /* GPIO 11 */
- };
-
- gpio@cb00 { /* GPIO 12 */
- };
-
- gpio@cc00 { /* GPIO 13 */
- };
-
- gpio@cd00 { /* GPIO 14 */
- };
-
- gpio@ce00 { /* GPIO 15 */
- qcom,mode = <1>;
- qcom,output-type = <0>;
- qcom,pull = <5>;
- qcom,vin-sel = <2>;
- qcom,out-strength = <3>;
- qcom,src-select = <2>;
- qcom,master-en = <1>;
- };
-
- gpio@cf00 { /* GPIO 16 */
- };
-
- gpio@d000 { /* GPIO 17 */
- };
-
- gpio@d100 { /* GPIO 18 */
- };
-
- gpio@d200 { /* GPIO 19 */
- qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
- qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
- qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
- qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
- qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
- qcom,src-select = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
- qcom,master-en = <1>;
- };
-
- gpio@d300 { /* GPIO 20 */
- };
-
- gpio@d400 { /* GPIO 21 */
- };
-
- gpio@d500 { /* GPIO 22 */
- };
-
- gpio@d600 { /* GPIO 23 */
- };
-
- gpio@d700 { /* GPIO 24 */
- };
-
- gpio@d800 { /* GPIO 25 */
- };
-
- gpio@d900 { /* GPIO 26 */
- };
-
- gpio@da00 { /* GPIO 27 */
- };
-
- gpio@db00 { /* GPIO 28 */
- };
-
- gpio@dc00 { /* GPIO 29 */
- qcom,pull = <0>; /* set to default pull */
- qcom,master-en = <1>;
- qcom,vin-sel = <2>; /* select 1.8 V source */
- };
-
- gpio@dd00 { /* GPIO 30 */
- };
-
- gpio@de00 { /* GPIO 31 */
- };
-
- gpio@df00 { /* GPIO 32 */
- };
-
- gpio@e000 { /* GPIO 33 */
- };
-
- gpio@e100 { /* GPIO 34 */
- };
-
- gpio@e200 { /* GPIO 35 */
- };
-
- gpio@e300 { /* GPIO 36 */
- };
-};
-
-&pm8941_mpps {
-
- mpp@a000 { /* MPP 1 */
- };
-
- mpp@a100 { /* MPP 2 */
- };
-
- mpp@a200 { /* MPP 3 */
- };
-
- mpp@a300 { /* MPP 4 */
- };
-
- mpp@a400 { /* MPP 5 */
- /* SPI_ETH config */
- qcom,mode = <1>; /* DIG_OUT */
- qcom,output-type = <0>; /* CMOS */
- qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
- qcom,src-select = <0>; /* CONSTANT */
- qcom,master-en = <1>; /* ENABLE MPP */
- };
-
- mpp@a500 { /* MPP 6 */
- /* SPI_ETH_RST config */
- qcom,mode = <1>; /* DIG_OUT */
- qcom,output-type = <0>; /* CMOS */
- qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
- qcom,src-select = <0>; /* CONSTANT */
- qcom,master-en = <1>; /* ENABLE MPP */
- };
-
- mpp@a600 { /* MPP 7 */
- };
-
- mpp@a700 { /* MPP 8 */
- };
-};
-
-&pm8841_mpps {
-
- mpp@a000 { /* MPP 1 */
- };
-
- mpp@a100 { /* MPP 2 */
- };
-
- mpp@a200 { /* MPP 3 */
- };
-
- mpp@a300 { /* MPP 4 */
- };
};
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
new file mode 100644
index 0000000..a55e6d4
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -0,0 +1,364 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "dsi-panel-toshiba-720p-video.dtsi"
+
+/ {
+ serial@f991e000 {
+ status = "ok";
+ };
+
+ qcom,mdss_dsi@fd922800 {
+ qcom,mdss_dsi_toshiba_720p_video {
+ status = "ok";
+ };
+ };
+
+ qcom,hdmi_tx@fd922100 {
+ status = "ok";
+ };
+
+ i2c@f9924000 {
+ atmel_mxt_ts@4a {
+ compatible = "atmel,mxt-ts";
+ reg = <0x4a>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <61 0x2>;
+ vdd_ana-supply = <&pm8941_l18>;
+ vcc_i2c-supply = <&pm8941_lvs1>;
+ atmel,reset-gpio = <&msmgpio 60 0x00>;
+ atmel,irq-gpio = <&msmgpio 61 0x00>;
+ atmel,panel-coords = <0 0 760 1424>;
+ atmel,display-coords = <0 0 720 1280>;
+ atmel,i2c-pull-up = <1>;
+ atmel,cfg_1 {
+ atmel,family-id = <0x82>;
+ atmel,variant-id = <0x19>;
+ atmel,version = <0x10>;
+ atmel,build = <0xaa>;
+ atmel,config = [
+ /* Object 6, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 38, Instance = 0 */
+ 15 00 02 10 08 0C 00 00
+ /* Object 7, Instance = 0 */
+ FF FF 32 03
+ /* Object 8, Instance = 0 */
+ 0F 00 0A 0A 00 00 0A 00 00 00
+ /* Object 9, Instance = 0 */
+ 83 00 00 18 0E 00 70 32 02 01
+ 00 03 01 01 05 0A 0A 0A 90 05
+ F8 02 00 00 0F 0F 00 00 48 2D
+ 07 0C 00 00 00 00
+ /* Object 15, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00
+ /* Object 18, Instance = 0 */
+ 00 00
+ /* Object 19, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 23, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00
+ /* Object 25, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00
+ /* Object 40, Instance = 0 */
+ 00 00 00 00 00
+ /* Object 42, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ /* Object 46, Instance = 0 */
+ 00 00 10 10 00 00 03 00 00 01
+ /* Object 47, Instance = 0 */
+ 08 0A 28 0A 02 0A 00 8C 00 20
+ 00 00 00
+ /* Object 55, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 56, Instance = 0 */
+ 03 00 01 18 05 05 05 05 05 05
+ 05 05 05 05 05 05 05 05 05 05
+ 05 05 05 05 05 05 05 05 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00
+ /* Object 57, Instance = 0 */
+ 00 00 00
+ /* Object 61, Instance = 0 */
+ 00 00 00 00 00
+ /* Object 61, Instance = 1 */
+ 00 00 00 00 00
+ /* Object 62, Instance = 0 */
+ 7F 03 00 16 00 00 00 00 00 00
+ 04 08 10 18 05 00 0A 05 05 50
+ 14 19 34 1A 64 00 00 04 40 00
+ 00 00 00 00 30 32 02 00 01 00
+ 05 00 00 00 00 00 00 00 00 00
+ 00 00 0C 00
+ ];
+ };
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&pm8941_gpios 3 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&pm8941_gpios 4 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&pm8941_gpios 5 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
+
+ spi@f9923000 {
+ ethernet-switch@2 {
+ compatible = "micrel,ks8851";
+ reg = <2>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <94 0>;
+ spi-max-frequency = <4800000>;
+ rst-gpio = <&pm8941_mpps 6 0>;
+ vdd-io-supply = <&spi_eth_vreg>;
+ vdd-phy-supply = <&spi_eth_vreg>;
+ };
+ };
+};
+
+&sdcc1 {
+ qcom,sdcc-bus-width = <4>;
+};
+
+&sdcc2 {
+ #address-cells = <0>;
+ interrupt-parent = <&sdcc2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 220 0
+ 2 &msmgpio 62 0x3>;
+ interrupt-names = "core_irq", "bam_irq", "status_irq";
+ cd-gpios = <&msmgpio 62 0x1>;
+};
+
+&pm8941_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+
+ gpio@c600 { /* GPIO 7 */
+ };
+
+ gpio@c700 { /* GPIO 8 */
+ };
+
+ gpio@c800 { /* GPIO 9 */
+ };
+
+ gpio@c900 { /* GPIO 10 */
+ };
+
+ gpio@ca00 { /* GPIO 11 */
+ };
+
+ gpio@cb00 { /* GPIO 12 */
+ };
+
+ gpio@cc00 { /* GPIO 13 */
+ };
+
+ gpio@cd00 { /* GPIO 14 */
+ };
+
+ gpio@ce00 { /* GPIO 15 */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <2>;
+ qcom,out-strength = <3>;
+ qcom,src-select = <2>;
+ qcom,master-en = <1>;
+ };
+
+ gpio@cf00 { /* GPIO 16 */
+ };
+
+ gpio@d000 { /* GPIO 17 */
+ };
+
+ gpio@d100 { /* GPIO 18 */
+ };
+
+ gpio@d200 { /* GPIO 19 */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
+ qcom,src-select = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
+ qcom,master-en = <1>;
+ };
+
+ gpio@d300 { /* GPIO 20 */
+ };
+
+ gpio@d400 { /* GPIO 21 */
+ };
+
+ gpio@d500 { /* GPIO 22 */
+ };
+
+ gpio@d600 { /* GPIO 23 */
+ };
+
+ gpio@d700 { /* GPIO 24 */
+ };
+
+ gpio@d800 { /* GPIO 25 */
+ };
+
+ gpio@d900 { /* GPIO 26 */
+ };
+
+ gpio@da00 { /* GPIO 27 */
+ };
+
+ gpio@db00 { /* GPIO 28 */
+ };
+
+ gpio@dc00 { /* GPIO 29 */
+ qcom,pull = <0>; /* set to default pull */
+ qcom,master-en = <1>;
+ qcom,vin-sel = <2>; /* select 1.8 V source */
+ };
+
+ gpio@dd00 { /* GPIO 30 */
+ };
+
+ gpio@de00 { /* GPIO 31 */
+ };
+
+ gpio@df00 { /* GPIO 32 */
+ };
+
+ gpio@e000 { /* GPIO 33 */
+ };
+
+ gpio@e100 { /* GPIO 34 */
+ };
+
+ gpio@e200 { /* GPIO 35 */
+ };
+
+ gpio@e300 { /* GPIO 36 */
+ };
+};
+
+&pm8941_mpps {
+
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ /* SPI_ETH config */
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+ qcom,src-select = <0>; /* CONSTANT */
+ qcom,master-en = <1>; /* ENABLE MPP */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ /* SPI_ETH_RST config */
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+ qcom,src-select = <0>; /* CONSTANT */
+ qcom,master-en = <1>; /* ENABLE MPP */
+ };
+
+ mpp@a600 { /* MPP 7 */
+ };
+
+ mpp@a700 { /* MPP 8 */
+ };
+};
+
+&pm8841_mpps {
+
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-liquid.dts b/arch/arm/boot/dts/msm8974-liquid.dts
index 2eacb46..ef38036 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dts
+++ b/arch/arm/boot/dts/msm8974-liquid.dts
@@ -13,378 +13,10 @@
/dts-v1/;
/include/ "msm8974.dtsi"
+/include/ "msm8974-liquid.dtsi"
/ {
model = "Qualcomm MSM 8974 LIQUID";
compatible = "qcom,msm8974-liquid", "qcom,msm8974";
qcom,msm-id = <126 9 0>;
-
- serial@f991e000 {
- status = "ok";
- };
-
- qcom,mdss_edp@fd923400 {
- status = "ok";
- };
-
- gpio_keys {
- compatible = "gpio-keys";
- input-name = "gpio-keys";
-
- home {
- label = "home";
- gpios = <&pm8941_gpios 1 0x1>;
- linux,input-type = <1>;
- linux,code = <102>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
-
- vol_down {
- label = "volume_down";
- gpios = <&pm8941_gpios 2 0x1>;
- linux,input-type = <1>;
- linux,code = <114>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
-
- vol_up {
- label = "volume_up";
- gpios = <&pm8941_gpios 5 0x1>;
- linux,input-type = <1>;
- linux,code = <115>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
- };
-
- qcom,mdss_mdp@fd900000 {
- qcom,memory-reservation-size = <0x1000000>; /* size 16MB */
- };
-
- qcom,hdmi_tx@fd922100 {
- status = "ok";
- };
-
- i2c@f9924000 {
- atmel_mxt_ts@4a {
- compatible = "atmel,mxt-ts";
- reg = <0x4a>;
- interrupt-parent = <&msmgpio>;
- interrupts = <61 0x2>;
- vdd_ana-supply = <&pm8941_l22>;
- vcc_i2c-supply = <&pm8941_s3>;
- atmel,reset-gpio = <&msmgpio 60 0x00>;
- atmel,irq-gpio = <&msmgpio 61 0x00>;
- atmel,panel-coords = <0 0 1080 1920>;
- atmel,display-coords = <0 0 1080 1920>;
- atmel,i2c-pull-up = <1>;
- atmel,cfg_1 {
- atmel,family-id = <0xa2>;
- atmel,variant-id = <0x00>;
- atmel,version = <0x11>;
- atmel,build = <0xaa>;
- atmel,config = [
- /* Object 6, Instance = 0 */
- 00 00 00 00 00 00
- /* Object 38, Instance = 0 */
- 16 00 00 14 09 0C 00 00 00 00
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00
- /* Object 7, Instance = 0 */
- FF FF 0A 03
- /* Object 8, Instance = 0 */
- 5F 00 14 14 00 00 00 01 00 00
- /* Object 9, Instance = 0 */
- 8F 00 00 20 34 00 87 3C 08 03
- 00 05 03 80 0A 14 14 0A 80 07
- 38 04 00 00 00 00 00 00 00 00
- 0F 0F 2E 33 02 00
- /* Object 15, Instance = 0 */
- 00 00 00 00 00 00 00 00 00 00
- 00
- /* Object 18, Instance = 0 */
- 04 00
- /* Object 24, Instance = 0 */
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00 00 00 00 00 00
- /* Object 25, Instance = 0 */
- 00 00 54 6F F0 55 00 00 00 00
- 00 00 00 00 00
- /* Object 27, Instance = 0 */
- 00 00 00 00 00 00 00
- /* Object 40, Instance = 0 */
- 00 14 14 14 14
- /* Object 42, Instance = 0 */
- 20 14 00 00 00 14 11 00 03 00
- /* Object 43, Instance = 0 */
- 09 00 01 01 91 00 80 00 00 00
- 00 00
- /* Object 46, Instance = 0 */
- 00 00 10 10 00 00 01 00 00 0F
- 0A
- /* Object 47, Instance = 0 */
- 00 14 23 02 05 1E 01 78 03 10
- 00 00 0C 00 00 00 00 00 00 00
- 00 00
- /* Object 55, Instance = 0 */
- 00 00 00 00 00 00 00
- /* Object 56, Instance = 0 */
- 02 00 01 30 13 14 14 14 15 15
- 15 15 15 15 15 16 16 16 16 16
- 16 16 16 16 16 15 14 14 14 14
- 15 14 14 14 14 13 00 00 01 02
- 05 05 00 00 00 00 00 00 00 00
- 00
- /* Object 57, Instance = 0 */
- 00 00 00
- /* Object 61, Instance = 0 */
- 00 00 00 00 00
- /* Object 62, Instance = 0 */
- 00 01 03 01 00 00 00 00 00 0A
- 0F 14 19 23 05 00 0A 05 05 69
- 23 23 34 11 64 06 06 04 40 00
- 00 00 00 00 69 4B 02 00 00 80
- 0A 14 14 18 18 10 10 80 00 80
- 00 00 0F 02 00 00 00 00 00 00
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00
- /* Object 63, Instance = 0 */
- 00 00 00 00 00 00 00 00 00 00
- 00 00
- ];
- };
- };
- };
-
- ext_5v: regulator-smb210 {
- compatible = "regulator-fixed";
- regulator-name = "ext_5v";
- gpio = <&pm8941_mpps 2 0>;
- enable-active-high;
- };
-};
-
-&pm8941_mvs1 {
- parent-supply = <&ext_5v>;
-};
-
-&pm8941_mvs2 {
- parent-supply = <&ext_5v>;
-};
-
-&pm8941_gpios {
- gpio@c000 { /* GPIO 1 */
- qcom,mode = <0>;
- qcom,pull = <0>;
- qcom,vin-sel = <2>;
- qcom,select = <0>;
- };
-
- gpio@c100 { /* GPIO 2 */
- qcom,mode = <0>;
- qcom,pull = <0>;
- qcom,vin-sel = <2>;
- qcom,select = <0>;
- };
-
- gpio@c200 { /* GPIO 3 */
- };
-
- gpio@c300 { /* GPIO 4 */
- };
-
- gpio@c400 { /* GPIO 5 */
- qcom,mode = <0>;
- qcom,pull = <0>;
- qcom,vin-sel = <2>;
- qcom,select = <0>;
- };
-
- gpio@c500 { /* GPIO 6 */
- };
-
- gpio@c600 { /* GPIO 7 */
- };
-
- gpio@c700 { /* GPIO 8 */
- };
-
- gpio@c800 { /* GPIO 9 */
- };
-
- gpio@c900 { /* GPIO 10 */
- };
-
- gpio@ca00 { /* GPIO 11 */
- };
-
- gpio@cb00 { /* GPIO 12 */
- };
-
- gpio@cc00 { /* GPIO 13 */
- };
-
- gpio@cd00 { /* GPIO 14 */
- };
-
- gpio@ce00 { /* GPIO 15 */
- qcom,mode = <1>;
- qcom,output-type = <0>;
- qcom,pull = <5>;
- qcom,vin-sel = <2>;
- qcom,out-strength = <3>;
- qcom,src-select = <2>;
- qcom,master-en = <1>;
- };
-
- gpio@cf00 { /* GPIO 16 */
- };
-
- gpio@d000 { /* GPIO 17 */
- };
-
- gpio@d100 { /* GPIO 18 */
- };
-
- gpio@d200 { /* GPIO 19 */
- qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
- qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
- qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
- qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
- qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
- qcom,src-select = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
- qcom,master-en = <1>;
- };
-
- gpio@d300 { /* GPIO 20 */
- };
-
- gpio@d400 { /* GPIO 21 */
- };
-
- gpio@d500 { /* GPIO 22 */
- };
-
- gpio@d600 { /* GPIO 23 */
- };
-
- gpio@d700 { /* GPIO 24 */
- };
-
- gpio@d800 { /* GPIO 25 */
- };
-
- gpio@d900 { /* GPIO 26 */
- };
-
- gpio@da00 { /* GPIO 27 */
- };
-
- gpio@db00 { /* GPIO 28 */
- };
-
- gpio@dc00 { /* GPIO 29 */
- qcom,pull = <0>; /* set to default pull */
- qcom,master-en = <1>;
- qcom,vin-sel = <2>; /* select 1.8 V source */
- };
-
- gpio@dd00 { /* GPIO 30 */
- };
-
- gpio@de00 { /* GPIO 31 */
- };
-
- gpio@df00 { /* GPIO 32 */
- };
-
- gpio@e000 { /* GPIO 33 */
- };
-
- gpio@e100 { /* GPIO 34 */
- };
-
- gpio@e200 { /* GPIO 35 */
- };
-
- gpio@e300 { /* GPIO 36 */
- };
-};
-
-&pm8941_mpps {
-
- mpp@a000 { /* MPP 1 */
- };
-
- mpp@a100 { /* MPP 2 */
- /* ext_5v regulator enable */
- qcom,mode = <1>; /* Digital output */
- qcom,invert = <0>; /* Output low initially */
- qcom,vin-sel = <2>; /* PM8941 S3 = 1.8 V */
- qcom,src-select = <0>; /* Constant */
- qcom,master-en = <1>; /* Enable MPP */
- };
-
- mpp@a200 { /* MPP 3 */
- };
-
- mpp@a300 { /* MPP 4 */
- };
-
- mpp@a400 { /* MPP 5 */
- /* SPI_ETH config */
- qcom,mode = <1>; /* DIG_OUT */
- qcom,output-type = <0>; /* CMOS */
- qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
- qcom,src-select = <0>; /* CONSTANT */
- qcom,master-en = <1>; /* ENABLE MPP */
- };
-
- mpp@a500 { /* MPP 6 */
- /* SPI_ETH_RST config */
- qcom,mode = <1>; /* DIG_OUT */
- qcom,output-type = <0>; /* CMOS */
- qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
- qcom,src-select = <0>; /* CONSTANT */
- qcom,master-en = <1>; /* ENABLE MPP */
- };
-
- mpp@a600 { /* MPP 7 */
- };
-
- mpp@a700 { /* MPP 8 */
- };
-};
-
-&pm8841_mpps {
-
- mpp@a000 { /* MPP 1 */
- };
-
- mpp@a100 { /* MPP 2 */
- };
-
- mpp@a200 { /* HDMI_MUX_SEL MPP 3*/
- status = "ok";
- qcom,mode = <1>; /* DIG_OUT */
- qcom,output-type = <0>; /* CMOS */
- qcom,vin-sel = <2>; /* PM8841_S3A 1.8V */
- qcom,src-select = <0>; /* CONSTANT */
- qcom,master-en = <1>; /* ENABLE MPP */
- };
-
- mpp@a300 { /* HDMI_MUX_EN MPP 4*/
- status = "ok";
- qcom,mode = <1>; /* DIG_OUT */
- qcom,output-type = <0>; /* CMOS */
- qcom,vin-sel = <0>; /* PM8841_VPH 3.4V */
- qcom,src-select = <0>; /* CONSTANT */
- qcom,master-en = <1>; /* ENABLE MPP */
- };
};
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
new file mode 100644
index 0000000..1e3d1b3
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -0,0 +1,396 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+ serial@f991e000 {
+ status = "ok";
+ };
+
+ qcom,mdss_edp@fd923400 {
+ status = "ok";
+ };
+
+ i2c@f9967000 {
+ battery@b {
+ compatible = "ti,bq28400-battery";
+ reg = <0xb>;
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+
+ home {
+ label = "home";
+ gpios = <&pm8941_gpios 1 0x1>;
+ linux,input-type = <1>;
+ linux,code = <102>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_down {
+ label = "volume_down";
+ gpios = <&pm8941_gpios 2 0x1>;
+ linux,input-type = <1>;
+ linux,code = <114>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&pm8941_gpios 5 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
+
+ qcom,mdss_mdp@fd900000 {
+ qcom,memory-reservation-size = <0x1000000>; /* size 16MB */
+ };
+
+ qcom,hdmi_tx@fd922100 {
+ status = "ok";
+ };
+
+ i2c@f9924000 {
+ atmel_mxt_ts@4a {
+ compatible = "atmel,mxt-ts";
+ reg = <0x4a>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <61 0x2>;
+ vdd_ana-supply = <&pm8941_l22>;
+ vcc_i2c-supply = <&pm8941_s3>;
+ atmel,reset-gpio = <&msmgpio 60 0x00>;
+ atmel,irq-gpio = <&msmgpio 61 0x00>;
+ atmel,panel-coords = <0 0 1080 1920>;
+ atmel,display-coords = <0 0 1080 1920>;
+ atmel,i2c-pull-up = <1>;
+ atmel,cfg_1 {
+ atmel,family-id = <0xa2>;
+ atmel,variant-id = <0x00>;
+ atmel,version = <0x11>;
+ atmel,build = <0xaa>;
+ atmel,config = [
+ /* Object 6, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 38, Instance = 0 */
+ 16 00 00 14 09 0C 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00
+ /* Object 7, Instance = 0 */
+ FF FF 0A 03
+ /* Object 8, Instance = 0 */
+ 5F 00 14 14 00 00 00 01 00 00
+ /* Object 9, Instance = 0 */
+ 8F 00 00 20 34 00 87 3C 08 03
+ 00 05 03 80 0A 14 14 0A 80 07
+ 38 04 00 00 00 00 00 00 00 00
+ 0F 0F 2E 33 02 00
+ /* Object 15, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00
+ /* Object 18, Instance = 0 */
+ 04 00
+ /* Object 24, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00
+ /* Object 25, Instance = 0 */
+ 00 00 54 6F F0 55 00 00 00 00
+ 00 00 00 00 00
+ /* Object 27, Instance = 0 */
+ 00 00 00 00 00 00 00
+ /* Object 40, Instance = 0 */
+ 00 14 14 14 14
+ /* Object 42, Instance = 0 */
+ 20 14 00 00 00 14 11 00 03 00
+ /* Object 43, Instance = 0 */
+ 09 00 01 01 91 00 80 00 00 00
+ 00 00
+ /* Object 46, Instance = 0 */
+ 00 00 10 10 00 00 01 00 00 0F
+ 0A
+ /* Object 47, Instance = 0 */
+ 00 14 23 02 05 1E 01 78 03 10
+ 00 00 0C 00 00 00 00 00 00 00
+ 00 00
+ /* Object 55, Instance = 0 */
+ 00 00 00 00 00 00 00
+ /* Object 56, Instance = 0 */
+ 02 00 01 30 13 14 14 14 15 15
+ 15 15 15 15 15 16 16 16 16 16
+ 16 16 16 16 16 15 14 14 14 14
+ 15 14 14 14 14 13 00 00 01 02
+ 05 05 00 00 00 00 00 00 00 00
+ 00
+ /* Object 57, Instance = 0 */
+ 00 00 00
+ /* Object 61, Instance = 0 */
+ 00 00 00 00 00
+ /* Object 62, Instance = 0 */
+ 00 01 03 01 00 00 00 00 00 0A
+ 0F 14 19 23 05 00 0A 05 05 69
+ 23 23 34 11 64 06 06 04 40 00
+ 00 00 00 00 69 4B 02 00 00 80
+ 0A 14 14 18 18 10 10 80 00 80
+ 00 00 0F 02 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00
+ /* Object 63, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00
+ ];
+ };
+ };
+ };
+
+ ext_5v: regulator-smb210 {
+ compatible = "regulator-fixed";
+ regulator-name = "ext_5v";
+ gpio = <&pm8941_mpps 2 0>;
+ enable-active-high;
+ };
+};
+
+&pm8941_mvs1 {
+ parent-supply = <&ext_5v>;
+};
+
+&pm8941_mvs2 {
+ parent-supply = <&ext_5v>;
+};
+
+&pm8941_gpios {
+ gpio@c000 { /* GPIO 1 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+
+ gpio@c600 { /* GPIO 7 */
+ };
+
+ gpio@c700 { /* GPIO 8 */
+ };
+
+ gpio@c800 { /* GPIO 9 */
+ };
+
+ gpio@c900 { /* GPIO 10 */
+ };
+
+ gpio@ca00 { /* GPIO 11 */
+ };
+
+ gpio@cb00 { /* GPIO 12 */
+ };
+
+ gpio@cc00 { /* GPIO 13 */
+ };
+
+ gpio@cd00 { /* GPIO 14 */
+ };
+
+ gpio@ce00 { /* GPIO 15 */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <2>;
+ qcom,out-strength = <3>;
+ qcom,src-select = <2>;
+ qcom,master-en = <1>;
+ };
+
+ gpio@cf00 { /* GPIO 16 */
+ };
+
+ gpio@d000 { /* GPIO 17 */
+ };
+
+ gpio@d100 { /* GPIO 18 */
+ };
+
+ gpio@d200 { /* GPIO 19 */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
+ qcom,src-select = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
+ qcom,master-en = <1>;
+ };
+
+ gpio@d300 { /* GPIO 20 */
+ };
+
+ gpio@d400 { /* GPIO 21 */
+ };
+
+ gpio@d500 { /* GPIO 22 */
+ };
+
+ gpio@d600 { /* GPIO 23 */
+ };
+
+ gpio@d700 { /* GPIO 24 */
+ };
+
+ gpio@d800 { /* GPIO 25 */
+ };
+
+ gpio@d900 { /* GPIO 26 */
+ };
+
+ gpio@da00 { /* GPIO 27 */
+ };
+
+ gpio@db00 { /* GPIO 28 */
+ };
+
+ gpio@dc00 { /* GPIO 29 */
+ qcom,pull = <0>; /* set to default pull */
+ qcom,master-en = <1>;
+ qcom,vin-sel = <2>; /* select 1.8 V source */
+ };
+
+ gpio@dd00 { /* GPIO 30 */
+ };
+
+ gpio@de00 { /* GPIO 31 */
+ };
+
+ gpio@df00 { /* GPIO 32 */
+ };
+
+ gpio@e000 { /* GPIO 33 */
+ };
+
+ gpio@e100 { /* GPIO 34 */
+ };
+
+ gpio@e200 { /* GPIO 35 */
+ };
+
+ gpio@e300 { /* GPIO 36 */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,out-strength = <3>; /* QPNP_PIN_OUT_STRENGTH_HIGH */
+ qcom,src-select = <3>; /* QPNP_PIN_SEL_FUNC_2 */
+ qcom,master-en = <1>;
+ };
+};
+
+&pm8941_mpps {
+
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ /* ext_5v regulator enable */
+ qcom,mode = <1>; /* Digital output */
+ qcom,invert = <0>; /* Output low initially */
+ qcom,vin-sel = <2>; /* PM8941 S3 = 1.8 V */
+ qcom,src-select = <0>; /* Constant */
+ qcom,master-en = <1>; /* Enable MPP */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ /* SPI_ETH config */
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+ qcom,src-select = <0>; /* CONSTANT */
+ qcom,master-en = <1>; /* ENABLE MPP */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ /* SPI_ETH_RST config */
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+ qcom,src-select = <0>; /* CONSTANT */
+ qcom,master-en = <1>; /* ENABLE MPP */
+ };
+
+ mpp@a600 { /* MPP 7 */
+ };
+
+ mpp@a700 { /* MPP 8 */
+ };
+};
+
+&pm8841_mpps {
+
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* HDMI_MUX_SEL MPP 3*/
+ status = "ok";
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <2>; /* PM8841_S3A 1.8V */
+ qcom,src-select = <0>; /* CONSTANT */
+ qcom,master-en = <1>; /* ENABLE MPP */
+ };
+
+ mpp@a300 { /* HDMI_MUX_EN MPP 4*/
+ status = "ok";
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <0>; /* PM8841_VPH 3.4V */
+ qcom,src-select = <0>; /* CONSTANT */
+ qcom,master-en = <1>; /* ENABLE MPP */
+ };
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index e791348..a51a38d 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -68,6 +68,9 @@
reg-names = "edp_base", "mmss_cc_base";
vdda-supply = <&pm8941_l12>;
gpio-panel-en = <&msmgpio 58 0>;
+ gpio-panel-pwm = <&pm8941_gpios 36 0>;
+ qcom,panel-lpg-channel = <7>; /* LPG Channel 8 */
+ qcom,panel-pwm-period = <53>;
status = "disable";
};
};
diff --git a/arch/arm/boot/dts/msm8974-mtp.dts b/arch/arm/boot/dts/msm8974-mtp.dts
index b63595b..9946cf0 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-mtp.dts
@@ -13,399 +13,10 @@
/dts-v1/;
/include/ "msm8974.dtsi"
-/include/ "dsi-panel-toshiba-720p-video.dtsi"
+/include/ "msm8974-mtp.dtsi"
/ {
model = "Qualcomm MSM 8974 MTP";
compatible = "qcom,msm8974-mtp", "qcom,msm8974";
qcom,msm-id = <126 8 0>;
-
- serial@f991e000 {
- status = "ok";
- };
-
- qcom,mdss_dsi@fd922800 {
- qcom,mdss_dsi_toshiba_720p_video {
- status = "ok";
- };
- };
-
- qcom,hdmi_tx@fd922100 {
- status = "disabled";
- };
-
- i2c@f9924000 {
- atmel_mxt_ts@4a {
- compatible = "atmel,mxt-ts";
- reg = <0x4a>;
- interrupt-parent = <&msmgpio>;
- interrupts = <61 0x2>;
- vdd_ana-supply = <&pm8941_l18>;
- vcc_i2c-supply = <&pm8941_lvs1>;
- atmel,reset-gpio = <&msmgpio 60 0x00>;
- atmel,irq-gpio = <&msmgpio 61 0x00>;
- atmel,panel-coords = <0 0 760 1424>;
- atmel,display-coords = <0 0 720 1280>;
- atmel,i2c-pull-up = <1>;
- atmel,cfg_1 {
- atmel,family-id = <0x82>;
- atmel,variant-id = <0x19>;
- atmel,version = <0x10>;
- atmel,build = <0xaa>;
- atmel,config = [
- /* Object 6, Instance = 0 */
- 00 00 00 00 00 00
- /* Object 38, Instance = 0 */
- 15 00 02 10 08 0C 00 00
- /* Object 7, Instance = 0 */
- FF FF 32 03
- /* Object 8, Instance = 0 */
- 0F 00 0A 0A 00 00 0A 00 00 00
- /* Object 9, Instance = 0 */
- 83 00 00 18 0E 00 70 32 02 01
- 00 03 01 01 05 0A 0A 0A 90 05
- F8 02 00 00 0F 0F 00 00 48 2D
- 07 0C 00 00 00 00
- /* Object 15, Instance = 0 */
- 00 00 00 00 00 00 00 00 00 00
- 00
- /* Object 18, Instance = 0 */
- 00 00
- /* Object 19, Instance = 0 */
- 00 00 00 00 00 00
- /* Object 23, Instance = 0 */
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00 00
- /* Object 25, Instance = 0 */
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00 00
- /* Object 40, Instance = 0 */
- 00 00 00 00 00
- /* Object 42, Instance = 0 */
- 00 00 00 00 00 00 00 00 00 00
- /* Object 46, Instance = 0 */
- 00 00 10 10 00 00 03 00 00 01
- /* Object 47, Instance = 0 */
- 08 0A 28 0A 02 0A 00 8C 00 20
- 00 00 00
- /* Object 55, Instance = 0 */
- 00 00 00 00 00 00
- /* Object 56, Instance = 0 */
- 03 00 01 18 05 05 05 05 05 05
- 05 05 05 05 05 05 05 05 05 05
- 05 05 05 05 05 05 05 05 00 00
- 00 00 00 00 00 00 00 00 00 00
- 00 00
- /* Object 57, Instance = 0 */
- 00 00 00
- /* Object 61, Instance = 0 */
- 00 00 00 00 00
- /* Object 61, Instance = 1 */
- 00 00 00 00 00
- /* Object 62, Instance = 0 */
- 7F 03 00 16 00 00 00 00 00 00
- 04 08 10 18 05 00 0A 05 05 50
- 14 19 34 1A 64 00 00 04 40 00
- 00 00 00 00 30 32 02 00 01 00
- 05 00 00 00 00 00 00 00 00 00
- 00 00 0C 00
- ];
- };
- };
- };
-
- gpio_keys {
- compatible = "gpio-keys";
- input-name = "gpio-keys";
-
- camera_snapshot {
- label = "camera_snapshot";
- gpios = <&pm8941_gpios 3 0x1>;
- linux,input-type = <1>;
- linux,code = <0x2fe>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
-
- camera_focus {
- label = "camera_focus";
- gpios = <&pm8941_gpios 4 0x1>;
- linux,input-type = <1>;
- linux,code = <0x210>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
-
- vol_up {
- label = "volume_up";
- gpios = <&pm8941_gpios 5 0x1>;
- linux,input-type = <1>;
- linux,code = <115>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
- };
-
- spi@f9923000 {
- ethernet-switch@2 {
- compatible = "micrel,ks8851";
- reg = <2>;
- interrupt-parent = <&msmgpio>;
- interrupts = <94 0>;
- spi-max-frequency = <4800000>;
- rst-gpio = <&pm8941_mpps 6 0>;
- vdd-io-supply = <&spi_eth_vreg>;
- vdd-phy-supply = <&spi_eth_vreg>;
- };
- };
-};
-
-&sdcc2 {
- #address-cells = <0>;
- interrupt-parent = <&sdcc2>;
- interrupts = <0 1 2>;
- #interrupt-cells = <1>;
- interrupt-map-mask = <0xffffffff>;
- interrupt-map = <0 &intc 0 125 0
- 1 &intc 0 220 0
- 2 &msmgpio 62 0x3>;
- interrupt-names = "core_irq", "bam_irq", "status_irq";
- cd-gpios = <&msmgpio 62 0x1>;
-};
-
-&usb_otg {
- qcom,hsusb-otg-otg-control = <2>;
-};
-
-&pm8941_chg {
- status = "ok";
-
- qcom,chg-charging-disabled;
-
- qcom,chg-chgr@1000 {
- status = "ok";
- };
-
- qcom,chg-buck@1100 {
- status = "ok";
- };
-
- qcom,chg-bat-if@1200 {
- status = "ok";
- };
-
- qcom,chg-usb-chgpth@1300 {
- status = "ok";
- };
-
- qcom,chg-dc-chgpth@1400 {
- status = "ok";
- };
-
- qcom,chg-boost@1500 {
- status = "ok";
- };
-
- qcom,chg-misc@1600 {
- status = "ok";
- };
-};
-
-&pm8941_gpios {
- gpio@c000 { /* GPIO 1 */
- };
-
- gpio@c100 { /* GPIO 2 */
- };
-
- gpio@c200 { /* GPIO 3 */
- qcom,mode = <0>;
- qcom,pull = <0>;
- qcom,vin-sel = <2>;
- qcom,select = <0>;
- };
-
- gpio@c300 { /* GPIO 4 */
- qcom,mode = <0>;
- qcom,pull = <0>;
- qcom,vin-sel = <2>;
- qcom,select = <0>;
- };
-
- gpio@c400 { /* GPIO 5 */
- qcom,mode = <0>;
- qcom,pull = <0>;
- qcom,vin-sel = <2>;
- qcom,select = <0>;
- };
-
- gpio@c500 { /* GPIO 6 */
- };
-
- gpio@c600 { /* GPIO 7 */
- };
-
- gpio@c700 { /* GPIO 8 */
- };
-
- gpio@c800 { /* GPIO 9 */
- };
-
- gpio@c900 { /* GPIO 10 */
- };
-
- gpio@ca00 { /* GPIO 11 */
- };
-
- gpio@cb00 { /* GPIO 12 */
- };
-
- gpio@cc00 { /* GPIO 13 */
- };
-
- gpio@cd00 { /* GPIO 14 */
- };
-
- gpio@ce00 { /* GPIO 15 */
- qcom,mode = <1>;
- qcom,output-type = <0>;
- qcom,pull = <5>;
- qcom,vin-sel = <2>;
- qcom,out-strength = <3>;
- qcom,src-select = <2>;
- qcom,master-en = <1>;
- };
-
- gpio@cf00 { /* GPIO 16 */
- };
-
- gpio@d000 { /* GPIO 17 */
- };
-
- gpio@d100 { /* GPIO 18 */
- };
-
- gpio@d200 { /* GPIO 19 */
- qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
- qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
- qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
- qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
- qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
- qcom,src-select = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
- qcom,master-en = <1>;
- };
-
- gpio@d300 { /* GPIO 20 */
- };
-
- gpio@d400 { /* GPIO 21 */
- };
-
- gpio@d500 { /* GPIO 22 */
- };
-
- gpio@d600 { /* GPIO 23 */
- };
-
- gpio@d700 { /* GPIO 24 */
- };
-
- gpio@d800 { /* GPIO 25 */
- };
-
- gpio@d900 { /* GPIO 26 */
- };
-
- gpio@da00 { /* GPIO 27 */
- };
-
- gpio@db00 { /* GPIO 28 */
- };
-
- gpio@dc00 { /* GPIO 29 */
- qcom,pull = <0>; /* set to default pull */
- qcom,master-en = <1>;
- qcom,vin-sel = <2>; /* select 1.8 V source */
- };
-
- gpio@dd00 { /* GPIO 30 */
- };
-
- gpio@de00 { /* GPIO 31 */
- };
-
- gpio@df00 { /* GPIO 32 */
- };
-
- gpio@e000 { /* GPIO 33 */
- };
-
- gpio@e100 { /* GPIO 34 */
- };
-
- gpio@e200 { /* GPIO 35 */
- };
-
- gpio@e300 { /* GPIO 36 */
- };
-};
-
-&pm8941_mpps {
-
- mpp@a000 { /* MPP 1 */
- };
-
- mpp@a100 { /* MPP 2 */
- };
-
- mpp@a200 { /* MPP 3 */
- };
-
- mpp@a300 { /* MPP 4 */
- };
-
- mpp@a400 { /* MPP 5 */
- /* SPI_ETH config */
- qcom,mode = <1>; /* DIG_OUT */
- qcom,output-type = <0>; /* CMOS */
- qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
- qcom,src-select = <0>; /* CONSTANT */
- qcom,master-en = <1>; /* ENABLE MPP */
- };
-
- mpp@a500 { /* MPP 6 */
- /* SPI_ETH_RST config */
- qcom,mode = <1>; /* DIG_OUT */
- qcom,output-type = <0>; /* CMOS */
- qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
- qcom,src-select = <0>; /* CONSTANT */
- qcom,master-en = <1>; /* ENABLE MPP */
- };
-
- mpp@a600 { /* MPP 7 */
- };
-
- mpp@a700 { /* MPP 8 */
- };
-};
-
-&pm8841_mpps {
-
- mpp@a000 { /* MPP 1 */
- };
-
- mpp@a100 { /* MPP 2 */
- };
-
- mpp@a200 { /* MPP 3 */
- };
-
- mpp@a300 { /* MPP 4 */
- };
-};
-
-&slim_msm {
- taiko_codec {
- qcom,cdc-micbias2-ext-cap;
- };
};
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
new file mode 100644
index 0000000..f1f4286
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -0,0 +1,408 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "dsi-panel-toshiba-720p-video.dtsi"
+
+/ {
+ serial@f991e000 {
+ status = "ok";
+ };
+
+ qcom,mdss_dsi@fd922800 {
+ qcom,mdss_dsi_toshiba_720p_video {
+ status = "ok";
+ };
+ };
+
+ qcom,hdmi_tx@fd922100 {
+ status = "disabled";
+ };
+
+ i2c@f9924000 {
+ atmel_mxt_ts@4a {
+ compatible = "atmel,mxt-ts";
+ reg = <0x4a>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <61 0x2>;
+ vdd_ana-supply = <&pm8941_l18>;
+ vcc_i2c-supply = <&pm8941_lvs1>;
+ atmel,reset-gpio = <&msmgpio 60 0x00>;
+ atmel,irq-gpio = <&msmgpio 61 0x00>;
+ atmel,panel-coords = <0 0 760 1424>;
+ atmel,display-coords = <0 0 720 1280>;
+ atmel,i2c-pull-up = <1>;
+ atmel,cfg_1 {
+ atmel,family-id = <0x82>;
+ atmel,variant-id = <0x19>;
+ atmel,version = <0x10>;
+ atmel,build = <0xaa>;
+ atmel,config = [
+ /* Object 6, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 38, Instance = 0 */
+ 15 00 02 10 08 0C 00 00
+ /* Object 7, Instance = 0 */
+ FF FF 32 03
+ /* Object 8, Instance = 0 */
+ 0F 00 0A 0A 00 00 0A 00 00 00
+ /* Object 9, Instance = 0 */
+ 83 00 00 18 0E 00 70 32 02 01
+ 00 03 01 01 05 0A 0A 0A 90 05
+ F8 02 00 00 0F 0F 00 00 48 2D
+ 07 0C 00 00 00 00
+ /* Object 15, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00
+ /* Object 18, Instance = 0 */
+ 00 00
+ /* Object 19, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 23, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00
+ /* Object 25, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00
+ /* Object 40, Instance = 0 */
+ 00 00 00 00 00
+ /* Object 42, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ /* Object 46, Instance = 0 */
+ 00 00 10 10 00 00 03 00 00 01
+ /* Object 47, Instance = 0 */
+ 08 0A 28 0A 02 0A 00 8C 00 20
+ 00 00 00
+ /* Object 55, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 56, Instance = 0 */
+ 03 00 01 18 05 05 05 05 05 05
+ 05 05 05 05 05 05 05 05 05 05
+ 05 05 05 05 05 05 05 05 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00
+ /* Object 57, Instance = 0 */
+ 00 00 00
+ /* Object 61, Instance = 0 */
+ 00 00 00 00 00
+ /* Object 61, Instance = 1 */
+ 00 00 00 00 00
+ /* Object 62, Instance = 0 */
+ 7F 03 00 16 00 00 00 00 00 00
+ 04 08 10 18 05 00 0A 05 05 50
+ 14 19 34 1A 64 00 00 04 40 00
+ 00 00 00 00 30 32 02 00 01 00
+ 05 00 00 00 00 00 00 00 00 00
+ 00 00 0C 00
+ ];
+ };
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&pm8941_gpios 3 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&pm8941_gpios 4 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&pm8941_gpios 5 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
+
+ spi@f9923000 {
+ ethernet-switch@2 {
+ compatible = "micrel,ks8851";
+ reg = <2>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <94 0>;
+ spi-max-frequency = <4800000>;
+ rst-gpio = <&pm8941_mpps 6 0>;
+ vdd-io-supply = <&spi_eth_vreg>;
+ vdd-phy-supply = <&spi_eth_vreg>;
+ };
+ };
+};
+
+&sdcc2 {
+ #address-cells = <0>;
+ interrupt-parent = <&sdcc2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 220 0
+ 2 &msmgpio 62 0x3>;
+ interrupt-names = "core_irq", "bam_irq", "status_irq";
+ cd-gpios = <&msmgpio 62 0x1>;
+};
+
+&usb_otg {
+ qcom,hsusb-otg-otg-control = <2>;
+};
+
+&usb3 {
+ qcom,dwc-usb3-msm-otg-capability;
+};
+
+&pm8941_chg {
+ status = "ok";
+
+ qcom,chg-charging-disabled;
+
+ qcom,chg-chgr@1000 {
+ status = "ok";
+ };
+
+ qcom,chg-buck@1100 {
+ status = "ok";
+ };
+
+ qcom,chg-bat-if@1200 {
+ status = "ok";
+ };
+
+ qcom,chg-usb-chgpth@1300 {
+ status = "ok";
+ };
+
+ qcom,chg-dc-chgpth@1400 {
+ status = "ok";
+ };
+
+ qcom,chg-boost@1500 {
+ status = "ok";
+ };
+
+ qcom,chg-misc@1600 {
+ status = "ok";
+ };
+};
+
+&pm8941_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+
+ gpio@c600 { /* GPIO 7 */
+ };
+
+ gpio@c700 { /* GPIO 8 */
+ };
+
+ gpio@c800 { /* GPIO 9 */
+ };
+
+ gpio@c900 { /* GPIO 10 */
+ };
+
+ gpio@ca00 { /* GPIO 11 */
+ };
+
+ gpio@cb00 { /* GPIO 12 */
+ };
+
+ gpio@cc00 { /* GPIO 13 */
+ };
+
+ gpio@cd00 { /* GPIO 14 */
+ };
+
+ gpio@ce00 { /* GPIO 15 */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <2>;
+ qcom,out-strength = <3>;
+ qcom,src-select = <2>;
+ qcom,master-en = <1>;
+ };
+
+ gpio@cf00 { /* GPIO 16 */
+ };
+
+ gpio@d000 { /* GPIO 17 */
+ };
+
+ gpio@d100 { /* GPIO 18 */
+ };
+
+ gpio@d200 { /* GPIO 19 */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
+ qcom,src-select = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
+ qcom,master-en = <1>;
+ };
+
+ gpio@d300 { /* GPIO 20 */
+ };
+
+ gpio@d400 { /* GPIO 21 */
+ };
+
+ gpio@d500 { /* GPIO 22 */
+ };
+
+ gpio@d600 { /* GPIO 23 */
+ };
+
+ gpio@d700 { /* GPIO 24 */
+ };
+
+ gpio@d800 { /* GPIO 25 */
+ };
+
+ gpio@d900 { /* GPIO 26 */
+ };
+
+ gpio@da00 { /* GPIO 27 */
+ };
+
+ gpio@db00 { /* GPIO 28 */
+ };
+
+ gpio@dc00 { /* GPIO 29 */
+ qcom,pull = <0>; /* set to default pull */
+ qcom,master-en = <1>;
+ qcom,vin-sel = <2>; /* select 1.8 V source */
+ };
+
+ gpio@dd00 { /* GPIO 30 */
+ };
+
+ gpio@de00 { /* GPIO 31 */
+ };
+
+ gpio@df00 { /* GPIO 32 */
+ };
+
+ gpio@e000 { /* GPIO 33 */
+ };
+
+ gpio@e100 { /* GPIO 34 */
+ };
+
+ gpio@e200 { /* GPIO 35 */
+ };
+
+ gpio@e300 { /* GPIO 36 */
+ };
+};
+
+&pm8941_mpps {
+
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ /* SPI_ETH config */
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+ qcom,src-select = <0>; /* CONSTANT */
+ qcom,master-en = <1>; /* ENABLE MPP */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ /* SPI_ETH_RST config */
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+ qcom,src-select = <0>; /* CONSTANT */
+ qcom,master-en = <1>; /* ENABLE MPP */
+ };
+
+ mpp@a600 { /* MPP 7 */
+ };
+
+ mpp@a700 { /* MPP 8 */
+ };
+};
+
+&pm8841_mpps {
+
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+};
+
+&slim_msm {
+ taiko_codec {
+ qcom,cdc-micbias2-ext-cap;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974_pm.dtsi b/arch/arm/boot/dts/msm8974-pm.dtsi
similarity index 100%
rename from arch/arm/boot/dts/msm8974_pm.dtsi
rename to arch/arm/boot/dts/msm8974-pm.dtsi
diff --git a/arch/arm/boot/dts/msm8974-rumi.dts b/arch/arm/boot/dts/msm8974-rumi.dts
index 3533151..738ff86 100644
--- a/arch/arm/boot/dts/msm8974-rumi.dts
+++ b/arch/arm/boot/dts/msm8974-rumi.dts
@@ -13,103 +13,10 @@
/dts-v1/;
/include/ "msm8974.dtsi"
+/include/ "msm8974-rumi.dtsi"
/ {
model = "Qualcomm MSM 8974 RUMI";
compatible = "qcom,msm8974-rumi", "qcom,msm8974";
qcom,msm-id = <126 15 0>;
-
- timer {
- clock-frequency = <5000000>;
- };
-
- serial@f995e000 {
- status = "ok";
- };
-
- usb@f9a55000 {
- status = "disable";
- };
-
- qcom,sdcc@f9824000 {
- qcom,sdcc-clk-rates = <400000 19200000>;
- };
-
- qcom,sdcc@f98a4000 {
- qcom,sdcc-clk-rates = <400000 19200000>;
- };
-
- qcom,sps@f998000 {
- status = "disable";
- };
-
- spi@f9924000 {
- status = "disable";
- };
-
- spi@f9923000 {
- compatible = "qcom,spi-qup-v2";
- reg = <0xf9923000 0x1000>;
- interrupts = <0 95 0>;
- spi-max-frequency = <24000000>;
- #address-cells = <1>;
- #size-cells = <0>;
- gpios = <&msmgpio 3 0>, /* CLK */
- <&msmgpio 1 0>, /* MISO */
- <&msmgpio 0 0>; /* MOSI */
- cs-gpios = <&msmgpio 9 0>;
-
- ethernet-switch@2 {
- compatible = "simtec,ks8851";
- reg = <2>;
- interrupt-parent = <&msmgpio>;
- interrupts = <90 0>;
- spi-max-frequency = <5000000>;
- };
- };
-
- i2c@f9966000 {
- status = "disable";
- };
-
- i2c@f9967000 {
- cell-index = <0>;
- compatible = "qcom,i2c-qup";
- reg = <0Xf9967000 0x1000>;
- reg-names = "qup_phys_addr";
- interrupts = <0 105 0>;
- interrupt-names = "qup_err_intr";
- qcom,i2c-bus-freq = <100000>;
- qcom,i2c-src-freq = <24000000>;
- gpios = <&msmgpio 83 0>, /* DAT */
- <&msmgpio 84 0>; /* CLK */
- };
-
- slim@fe12f000 {
- status = "disable";
- };
-
- qcom,mdss_dsi@fd922800 {
- status = "disable";
- };
-
- qcom,spmi@fc4c0000 {
- status = "disable";
- };
-
- qcom,ssusb@F9200000 {
- status = "disable";
- };
-
- qcom,lpass@fe200000 {
- status = "disable";
- };
-
- qcom,pronto@fb21b000 {
- status = "disable";
- };
-
- qcom,mss@fc880000 {
- status = "disable";
- };
};
diff --git a/arch/arm/boot/dts/msm8974-rumi.dtsi b/arch/arm/boot/dts/msm8974-rumi.dtsi
new file mode 100644
index 0000000..d4b7793
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-rumi.dtsi
@@ -0,0 +1,107 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+ timer {
+ clock-frequency = <5000000>;
+ };
+
+ serial@f995e000 {
+ status = "ok";
+ };
+
+ usb@f9a55000 {
+ status = "disable";
+ };
+
+ qcom,sdcc@f9824000 {
+ qcom,sdcc-clk-rates = <400000 19200000>;
+ };
+
+ qcom,sdcc@f98a4000 {
+ qcom,sdcc-clk-rates = <400000 19200000>;
+ };
+
+ qcom,sps@f998000 {
+ status = "disable";
+ };
+
+ spi@f9924000 {
+ status = "disable";
+ };
+
+ spi@f9923000 {
+ compatible = "qcom,spi-qup-v2";
+ reg = <0xf9923000 0x1000>;
+ interrupts = <0 95 0>;
+ spi-max-frequency = <24000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ gpios = <&msmgpio 3 0>, /* CLK */
+ <&msmgpio 1 0>, /* MISO */
+ <&msmgpio 0 0>; /* MOSI */
+ cs-gpios = <&msmgpio 9 0>;
+
+ ethernet-switch@2 {
+ compatible = "simtec,ks8851";
+ reg = <2>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <90 0>;
+ spi-max-frequency = <5000000>;
+ };
+ };
+
+ i2c@f9966000 {
+ status = "disable";
+ };
+
+ i2c@f9967000 {
+ cell-index = <0>;
+ compatible = "qcom,i2c-qup";
+ reg = <0Xf9967000 0x1000>;
+ reg-names = "qup_phys_addr";
+ interrupts = <0 105 0>;
+ interrupt-names = "qup_err_intr";
+ qcom,i2c-bus-freq = <100000>;
+ qcom,i2c-src-freq = <24000000>;
+ gpios = <&msmgpio 83 0>, /* DAT */
+ <&msmgpio 84 0>; /* CLK */
+ };
+
+ slim@fe12f000 {
+ status = "disable";
+ };
+
+ qcom,mdss_dsi@fd922800 {
+ status = "disable";
+ };
+
+ qcom,spmi@fc4c0000 {
+ status = "disable";
+ };
+
+ qcom,ssusb@F9200000 {
+ status = "disable";
+ };
+
+ qcom,lpass@fe200000 {
+ status = "disable";
+ };
+
+ qcom,pronto@fb21b000 {
+ status = "disable";
+ };
+
+ qcom,mss@fc880000 {
+ status = "disable";
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-sim.dts b/arch/arm/boot/dts/msm8974-sim.dts
index d5368fa..09ea419 100644
--- a/arch/arm/boot/dts/msm8974-sim.dts
+++ b/arch/arm/boot/dts/msm8974-sim.dts
@@ -13,86 +13,10 @@
/dts-v1/;
/include/ "msm8974.dtsi"
-/include/ "dsi-panel-sim-video.dtsi"
+/include/ "msm8974-sim.dtsi"
/ {
model = "Qualcomm MSM 8974 Simulator";
compatible = "qcom,msm8974-sim", "qcom,msm8974";
qcom,msm-id = <126 16 0>;
-
- qcom,mdss_dsi@fd922800 {
- qcom,mdss_dsi_sim_video {
- status = "ok";
- };
- };
-
- serial@f991f000 {
- status = "ok";
- };
-
- serial@f995e000 {
- status = "ok";
- };
-};
-
-&jpeg_iommu {
- qcom,iommu-ctx@fda6c000 {
- interrupts = <0 69 0>;
- };
-
- qcom,iommu-ctx@fda6d000 {
- interrupts = <0 70 0>;
- };
-
- qcom,iommu-ctx@fda6e000 {
- interrupts = <0 71 0>;
- };
-};
-
-&mdp_iommu {
- qcom,iommu-ctx@fd930000 {
- interrupts = <0 46 0>;
- };
-
- qcom,iommu-ctx@fd931000 {
- interrupts = <0 47 0>;
- };
-};
-
-&venus_iommu {
- qcom,iommu-ctx@fdc8c000 {
- interrupts = <0 43 0>;
- };
-
- qcom,iommu-ctx@fdc8d000 {
- interrupts = <0 42 0>;
- };
-
- qcom,iommu-ctx@fdc8e000 {
- interrupts = <0 41 0>;
- };
-};
-
-&kgsl_iommu {
- qcom,iommu-ctx@fdb18000 {
- interrupts = <0 240 0>;
- };
-
- qcom,iommu-ctx@fdb19000 {
- interrupts = <0 241 0>;
- };
-};
-
-&vfe_iommu {
- qcom,iommu-ctx@fda4c000 {
- interrupts = <0 64 0>;
- };
-
- qcom,iommu-ctx@fda4d000 {
- interrupts = <0 65 0>;
- };
-
- qcom,iommu-ctx@fda4e000 {
- interrupts = <0 66 0>;
- };
};
diff --git a/arch/arm/boot/dts/msm8974-sim.dtsi b/arch/arm/boot/dts/msm8974-sim.dtsi
new file mode 100644
index 0000000..41e37de
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-sim.dtsi
@@ -0,0 +1,91 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "dsi-panel-sim-video.dtsi"
+
+/ {
+ qcom,mdss_dsi@fd922800 {
+ qcom,mdss_dsi_sim_video {
+ status = "ok";
+ };
+ };
+
+ serial@f991f000 {
+ status = "ok";
+ };
+
+ serial@f995e000 {
+ status = "ok";
+ };
+};
+
+&jpeg_iommu {
+ qcom,iommu-ctx@fda6c000 {
+ interrupts = <0 69 0>;
+ };
+
+ qcom,iommu-ctx@fda6d000 {
+ interrupts = <0 70 0>;
+ };
+
+ qcom,iommu-ctx@fda6e000 {
+ interrupts = <0 71 0>;
+ };
+};
+
+&mdp_iommu {
+ qcom,iommu-ctx@fd930000 {
+ interrupts = <0 46 0>;
+ };
+
+ qcom,iommu-ctx@fd931000 {
+ interrupts = <0 47 0>;
+ };
+};
+
+&venus_iommu {
+ qcom,iommu-ctx@fdc8c000 {
+ interrupts = <0 43 0>;
+ };
+
+ qcom,iommu-ctx@fdc8d000 {
+ interrupts = <0 42 0>;
+ };
+
+ qcom,iommu-ctx@fdc8e000 {
+ interrupts = <0 41 0>;
+ };
+};
+
+&kgsl_iommu {
+ qcom,iommu-ctx@fdb18000 {
+ interrupts = <0 240 0>;
+ };
+
+ qcom,iommu-ctx@fdb19000 {
+ interrupts = <0 241 0>;
+ };
+};
+
+&vfe_iommu {
+ qcom,iommu-ctx@fda4c000 {
+ interrupts = <0 64 0>;
+ };
+
+ qcom,iommu-ctx@fda4d000 {
+ interrupts = <0 65 0>;
+ };
+
+ qcom,iommu-ctx@fda4e000 {
+ interrupts = <0 66 0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 3f51ec9..6b65837 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -11,7 +11,7 @@
*/
/include/ "skeleton.dtsi"
-/include/ "msm8974_pm.dtsi"
+/include/ "msm8974-pm.dtsi"
/include/ "msm8974-iommu.dtsi"
/include/ "msm8974-camera.dtsi"
/include/ "msm8974-coresight.dtsi"
@@ -261,6 +261,23 @@
<&msmgpio 54 0>, /* MISO */
<&msmgpio 53 0>; /* MOSI */
cs-gpios = <&msmgpio 55 0>;
+
+ epm-adc@0 {
+ compatible = "cy,epm-adc-cy8c5568lti-114";
+ reg = <0>;
+ interrupt-parent = <&msmgpio>;
+ spi-max-frequency = <960000>;
+ qcom,channels = <31>;
+ qcom,gain = <100 100 100 50 100 100 1 100 1 50
+ 1 100 1 100 50 50 50 50 50 50
+ 100 50 100 50 50 50 50 50 50 50
+ 50>;
+ qcom,rsense = <2 2 2 200 20 2 1 2 1 30
+ 1 10 1 30 50 30 500 30 100 30
+ 100 500 20 200 1000 20 1000 1000 70 200
+ 50>;
+ qcom,channel-type = <0x2a40>;
+ };
};
slim_msm: slim@fe12f000 {
@@ -511,19 +528,23 @@
qcom,pm8941@1 {
qcom,leds@d800 {
- qcom,name = "wled:backlight";
- linux,default-trigger = "bkl-trigger";
- qcom,cs-out-en;
- qcom,op-fdbck;
- qcom,default-state = "on";
- qcom,max-current = <25>;
- qcom,ctrl-delay-us = <0>;
- qcom,boost-curr-lim = <3>;
- qcom,cp-sel = <0>;
- qcom,switch-freq = <2>;
- qcom,ovp-val = <2>;
- qcom,num-strings = <1>;
status = "okay";
+ qcom,wled_0 {
+ label = "wled";
+ linux,name = "wled:backlight";
+ linux,default-trigger = "bkl-trigger";
+ qcom,cs-out-en;
+ qcom,op-fdbck;
+ qcom,default-state = "on";
+ qcom,max-current = <25>;
+ qcom,ctrl-delay-us = <0>;
+ qcom,boost-curr-lim = <3>;
+ qcom,cp-sel = <0>;
+ qcom,switch-freq = <2>;
+ qcom,ovp-val = <2>;
+ qcom,num-strings = <1>;
+ qcom,id = <0>;
+ };
};
qcom,leds@d900 {
@@ -564,10 +585,12 @@
};
};
- i2c@f9967000 {
+ i2c@f9967000 { /* BLSP#11 */
cell-index = <0>;
compatible = "qcom,i2c-qup";
reg = <0Xf9967000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
reg-names = "qup_phys_addr";
interrupts = <0 105 0>;
interrupt-names = "qup_err_intr";
@@ -628,17 +651,18 @@
l2_hfpll_b-supply = <&pm8941_l12_ao>;
};
- qcom,ssusb@f9200000 {
+ usb3: qcom,ssusb@f9200000 {
compatible = "qcom,dwc-usb3-msm";
reg = <0xf9200000 0xfc000>,
<0xfd4ab000 0x4>;
- interrupts = <0 131 0 0 179 0>;
- interrupt-names = "irq", "otg_irq";
+ interrupts = <0 131 0>, <0 179 0>, <0 133 0>;
+ interrupt-names = "irq", "otg_irq", "hs_phy_irq";
SSUSB_VDDCX-supply = <&pm8841_s2>;
SSUSB_1p8-supply = <&pm8941_l6>;
HSUSB_VDDCX-supply = <&pm8841_s2>;
HSUSB_1p8-supply = <&pm8941_l6>;
HSUSB_3p3-supply = <&pm8941_l24>;
+ vbus_dwc3-supply = <&pm8941_mvs1>;
qcom,dwc-usb3-msm-dbm-eps = <4>;
qcom,msm-bus,name = "usb3";
@@ -804,10 +828,9 @@
reg = <0xfc880000 0x100>,
<0xfd485000 0x400>,
<0xfc820000 0x020>,
- <0xfc401680 0x004>,
- <0xfc980008 0x004>;
+ <0xfc401680 0x004>;
reg-names = "qdsp6_base", "halt_base", "rmb_base",
- "restart_reg", "clamp_reg";
+ "restart_reg";
vdd_mss-supply = <&pm8841_s3>;
@@ -1041,7 +1064,7 @@
qcom,dst-bam-physical-address = <0xf9304000>;
qcom,dst-bam-pipe-index = <2>;
qcom,data-fifo-offset = <0xf0000>;
- qcom,data-fifo-size = <0x4000>;
+ qcom,data-fifo-size = <0x1800>;
qcom,descriptor-fifo-offset = <0xf4000>;
qcom,descriptor-fifo-size = <0x1400>;
};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 2f2518d..0ebeb9c 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -250,6 +250,12 @@
a5_cpu-supply = <&pm8019_l10_corner_ao>;
a5_mem-supply = <&pm8019_l12_ao>;
};
+
+ gdsc_usb_hsic: qcom,gdsc@fc400404 {
+ compatible = "qcom,gdsc";
+ reg = <0xfc400404 0x4>;
+ regulator-name = "gdsc_usb_hsic";
+ };
};
/include/ "msm-pm8019-rpm-regulator.dtsi"
diff --git a/arch/arm/configs/fsm9xxx-perf_defconfig b/arch/arm/configs/fsm9xxx-perf_defconfig
index 93e84e9..1dc853b 100644
--- a/arch/arm/configs/fsm9xxx-perf_defconfig
+++ b/arch/arm/configs/fsm9xxx-perf_defconfig
@@ -11,7 +11,6 @@
CONFIG_PANIC_TIMEOUT=5
CONFIG_ASHMEM=y
CONFIG_EMBEDDED=y
-# CONFIG_PERF_EVENTS is not set
CONFIG_SLAB=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
@@ -84,6 +83,7 @@
CONFIG_IPV6_MROUTE=y
CONFIG_IPV6_PIMSM_V2=y
# CONFIG_NET_ACTIVITY_STATS is not set
+CONFIG_IP_SCTP=y
CONFIG_RFKILL=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
diff --git a/arch/arm/configs/fsm9xxx_defconfig b/arch/arm/configs/fsm9xxx_defconfig
index c45063f..203d3b7 100644
--- a/arch/arm/configs/fsm9xxx_defconfig
+++ b/arch/arm/configs/fsm9xxx_defconfig
@@ -12,7 +12,6 @@
CONFIG_KALLSYMS_ALL=y
CONFIG_ASHMEM=y
CONFIG_EMBEDDED=y
-# CONFIG_PERF_EVENTS is not set
CONFIG_SLAB=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
@@ -83,6 +82,7 @@
CONFIG_IPV6_MROUTE=y
CONFIG_IPV6_PIMSM_V2=y
# CONFIG_NET_ACTIVITY_STATS is not set
+CONFIG_IP_SCTP=y
CONFIG_RFKILL=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
diff --git a/arch/arm/configs/msm8910_defconfig b/arch/arm/configs/msm8910_defconfig
index e4dd4fb..83a499b 100644
--- a/arch/arm/configs/msm8910_defconfig
+++ b/arch/arm/configs/msm8910_defconfig
@@ -69,6 +69,8 @@
CONFIG_DEBUG_GPIO=y
CONFIG_GPIO_SYSFS=y
# CONFIG_HWMON is not set
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_STUB=y
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_SOC=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 53e6260..ec00b68 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -367,6 +367,7 @@
CONFIG_S5K3L1YX=y
CONFIG_IMX091=y
CONFIG_MSM_WFD=y
+CONFIG_IMX135=y
CONFIG_RADIO_IRIS=y
CONFIG_RADIO_IRIS_TRANSPORT=m
# CONFIG_DVB_FE_CUSTOMISE is not set
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 5770859..33f7987 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -371,6 +371,7 @@
CONFIG_S5K3L1YX=y
CONFIG_IMX091=y
CONFIG_MSM_WFD=y
+CONFIG_IMX135=y
CONFIG_RADIO_IRIS=y
CONFIG_RADIO_IRIS_TRANSPORT=m
# CONFIG_DVB_FE_CUSTOMISE is not set
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index b2ee503..98c1ede 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -50,6 +50,7 @@
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
# CONFIG_MSM_HW3D is not set
CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
CONFIG_MSM_PIL_LPASS_QDSP6V5=y
CONFIG_MSM_PIL_MSS_QDSP6V5=y
CONFIG_MSM_PIL_MBA=y
@@ -269,11 +270,14 @@
CONFIG_GPIO_QPNP_PIN=y
CONFIG_GPIO_QPNP_PIN_DEBUG=y
CONFIG_POWER_SUPPLY=y
-# CONFIG_BATTERY_MSM is not set
+CONFIG_BATTERY_BQ28400=y
+CONFIG_QPNP_CHARGER=y
+CONFIG_QPNP_BMS=y
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
CONFIG_SENSORS_QPNP_ADC_CURRENT=y
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_QPNP=y
CONFIG_WCD9320_CODEC=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_STUB=y
@@ -297,6 +301,7 @@
CONFIG_MSM_CSI2_REGISTER=y
CONFIG_MSM_ISPIF=y
CONFIG_S5K3L1YX=y
+CONFIG_MSM_WFD=y
CONFIG_RADIO_IRIS=y
CONFIG_RADIO_IRIS_TRANSPORT=m
CONFIG_ION=y
@@ -365,6 +370,7 @@
CONFIG_USB_BAM=y
CONFIG_SPS_SUPPORT_BAMDMA=y
CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_PWM=y
CONFIG_QPNP_POWER_ON=y
CONFIG_QPNP_CLKDIV=y
CONFIG_MSM_IOMMU=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index d8d2eae..328a4dc 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -36,7 +36,6 @@
CONFIG_EFI_PARTITION=y
CONFIG_ARCH_MSM=y
CONFIG_ARCH_MSM8974=y
-CONFIG_ARCH_MSM8226=y
CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
# CONFIG_MSM_STACKED_MEMORY is not set
CONFIG_CPU_HAS_L2_PMU=y
@@ -272,7 +271,7 @@
CONFIG_GPIO_QPNP_PIN=y
CONFIG_GPIO_QPNP_PIN_DEBUG=y
CONFIG_POWER_SUPPLY=y
-# CONFIG_BATTERY_MSM is not set
+CONFIG_BATTERY_BQ28400=y
CONFIG_QPNP_CHARGER=y
CONFIG_QPNP_BMS=y
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
@@ -284,7 +283,6 @@
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_STUB=y
CONFIG_REGULATOR_QPNP=y
-CONFIG_QPNP_PWM=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_DEV=y
@@ -373,6 +371,7 @@
CONFIG_USB_BAM=y
CONFIG_SPS_SUPPORT_BAMDMA=y
CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_PWM=y
CONFIG_QPNP_POWER_ON=y
CONFIG_QPNP_CLKDIV=y
CONFIG_MSM_IOMMU=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 36f417e..e1d4ca0 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -85,6 +85,13 @@
# CONFIG_NET_VENDOR_CIRRUS is not set
# CONFIG_NET_VENDOR_FARADAY is not set
# CONFIG_NET_VENDOR_INTEL is not set
+CONFIG_WIRELESS=y
+CONFIG_CFG80211=m
+CONFIG_NL80211_TESTMODE=y
+CONFIG_ATH_COMMON=m
+CONFIG_ATH6KL=m
+CONFIG_ATH6KL_SDIO=m
+CONFIG_ATH6KL_DEBUG=y
CONFIG_KS8851=y
# CONFIG_NET_VENDOR_MICROCHIP is not set
# CONFIG_MSM_RMNET is not set
@@ -120,6 +127,7 @@
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_QPNP_PIN=y
CONFIG_GPIO_QPNP_PIN_DEBUG=y
+CONFIG_POWER_SUPPLY=y
CONFIG_HWMON=y
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
CONFIG_REGULATOR=y
diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h
index 53426c6..12f71a1 100644
--- a/arch/arm/include/asm/outercache.h
+++ b/arch/arm/include/asm/outercache.h
@@ -92,6 +92,7 @@
static inline void outer_flush_all(void) { }
static inline void outer_inv_all(void) { }
static inline void outer_disable(void) { }
+static inline void outer_resume(void) { }
#endif
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 3f36017..73e1ad2 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -264,6 +264,7 @@
select MSM_RPM_REGULATOR_SMD
select ARM_HAS_SG_CHAIN
select MSM_RUN_QUEUE_STATS
+ select MEMORY_HOLE_CARVEOUT
config ARCH_MPQ8092
bool "MPQ8092"
@@ -2004,7 +2005,7 @@
config MSM_PIL_TZAPPS
tristate "TZApps Boot Support"
- depends on MSM_PIL
+ depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
help
Support for booting and shutting down TZApps.
@@ -2023,13 +2024,13 @@
config MSM_PIL_VIDC
tristate "Video Core Secure Boot Support"
- depends on MSM_PIL
+ depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
help
Support for authenticating the video core image.
config MSM_PIL_VENUS
tristate "VENUS (Video) Boot Support"
- depends on MSM_PIL
+ depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
help
Support for booting and shutting down the VENUS processor (Video).
Venus is the Video subsystem processor used for video codecs.
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 11d2d2f..fe5fe8c 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -293,6 +293,7 @@
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 clock-mdss-8974.o
obj-$(CONFIG_ARCH_MSM8974) += gdsc.o
+obj-$(CONFIG_ARCH_MSM9625) += gdsc.o
obj-$(CONFIG_ARCH_MSM8974) += krait-regulator.o
obj-$(CONFIG_ARCH_MSM9625) += board-9625.o board-9625-gpiomux.o
obj-$(CONFIG_ARCH_MSM9625) += clock-local2.o clock-pll.o clock-9625.o clock-rpm.o clock-voter.o acpuclock-9625.o
@@ -330,7 +331,7 @@
endif
obj-$(CONFIG_MSM_MPM_OF) += mpm-of.o
obj-$(CONFIG_MSM_MPM) += mpm.o
-obj-$(CONFIG_MSM_RPM_STATS_LOG) += rpm_stats.o
+obj-$(CONFIG_MSM_RPM_STATS_LOG) += rpm_stats.o rpm_master_stat.o
obj-$(CONFIG_MSM_RPM_RBCPR_STATS_LOG) += rpm_rbcpr_stats.o
obj-$(CONFIG_MSM_RPM_LOG) += rpm_log.o
obj-$(CONFIG_MSM_TZ_LOG) += tz_log.o
@@ -401,3 +402,5 @@
endif
obj-$(CONFIG_MSM_FIQ) += msm7k_fiq.o
obj-$(CONFIG_MSM_FIQ) += msm7k_fiq_handler.o
+
+obj-$(CONFIG_MEMORY_HOLE_CARVEOUT) += msm_mem_hole.o
diff --git a/arch/arm/mach-msm/acpuclock-krait-debug.c b/arch/arm/mach-msm/acpuclock-krait-debug.c
index 0ab70b4..a29735e 100644
--- a/arch/arm/mach-msm/acpuclock-krait-debug.c
+++ b/arch/arm/mach-msm/acpuclock-krait-debug.c
@@ -35,7 +35,7 @@
bool set;
bool enable;
};
-static int l2_acg_en_val[MAX_SCALABLES];
+static int l2_acg_en_val;
static struct dentry *base_dir;
static struct dentry *sc_dir[MAX_SCALABLES];
@@ -51,8 +51,8 @@
val &= ~BIT(0);
else
val |= BIT(0);
- asm volatile ("mcr p15, 7, %[l2cpdr], c15, c0, 5\n\t"
- : : [l2cpdr]"r" (val));
+ asm volatile ("mcr p15, 7, %[cpmr0], c15, c0, 5\n\t"
+ : : [cpmr0]"r" (val));
} else {
action->enable = !(val & BIT(0));
}
@@ -65,7 +65,7 @@
if (sc_id == L2) {
regval = get_l2_indirect_reg(drv->scalable[sc_id].l2cpmr_iaddr);
- l2_acg_en_val[sc_id] = regval & (0x3 << 10);
+ l2_acg_en_val = regval & (0x3 << 10);
regval |= (0x3 << 10);
set_l2_indirect_reg(drv->scalable[sc_id].l2cpmr_iaddr, regval);
} else {
@@ -82,7 +82,7 @@
if (sc_id == L2) {
regval = get_l2_indirect_reg(drv->scalable[sc_id].l2cpmr_iaddr);
regval &= ~(0x3 << 10);
- regval |= l2_acg_en_val[sc_id];
+ regval |= l2_acg_en_val;
set_l2_indirect_reg(drv->scalable[sc_id].l2cpmr_iaddr, regval);
} else {
struct acg_action action = { .set = true, .enable = true };
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index a386e78..bf57eab 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -209,7 +209,8 @@
}
/* Set the CPU or L2 clock speed. */
-static void set_speed(struct scalable *sc, const struct core_speed *tgt_s)
+static void set_speed(struct scalable *sc, const struct core_speed *tgt_s,
+ bool skip_regulators)
{
const struct core_speed *strt_s = sc->cur_speed;
@@ -232,10 +233,10 @@
set_pri_clk_src(sc, tgt_s->pri_src_sel);
} else if (strt_s->src == HFPLL && tgt_s->src != HFPLL) {
set_pri_clk_src(sc, tgt_s->pri_src_sel);
- hfpll_disable(sc, false);
+ hfpll_disable(sc, skip_regulators);
} else if (strt_s->src != HFPLL && tgt_s->src == HFPLL) {
hfpll_set_rate(sc, tgt_s);
- hfpll_enable(sc, false);
+ hfpll_enable(sc, skip_regulators);
set_pri_clk_src(sc, tgt_s->pri_src_sel);
}
@@ -426,6 +427,47 @@
return tgt->vdd_core + (enable_boost ? drv.boost_uv : 0);
}
+static DEFINE_MUTEX(l2_regulator_lock);
+static int l2_vreg_count;
+
+static int enable_l2_regulators(void)
+{
+ int ret = 0;
+
+ mutex_lock(&l2_regulator_lock);
+ if (l2_vreg_count == 0) {
+ ret = enable_rpm_vreg(&drv.scalable[L2].vreg[VREG_HFPLL_A]);
+ if (ret)
+ goto out;
+ ret = enable_rpm_vreg(&drv.scalable[L2].vreg[VREG_HFPLL_B]);
+ if (ret) {
+ disable_rpm_vreg(&drv.scalable[L2].vreg[VREG_HFPLL_A]);
+ goto out;
+ }
+ }
+ l2_vreg_count++;
+out:
+ mutex_unlock(&l2_regulator_lock);
+
+ return ret;
+}
+
+static void disable_l2_regulators(void)
+{
+ mutex_lock(&l2_regulator_lock);
+
+ if (WARN(!l2_vreg_count, "L2 regulator votes are unbalanced!"))
+ goto out;
+
+ if (l2_vreg_count == 1) {
+ disable_rpm_vreg(&drv.scalable[L2].vreg[VREG_HFPLL_B]);
+ disable_rpm_vreg(&drv.scalable[L2].vreg[VREG_HFPLL_A]);
+ }
+ l2_vreg_count--;
+out:
+ mutex_unlock(&l2_regulator_lock);
+}
+
/* Set the CPU's clock rate and adjust the L2 rate, voltage and BW requests. */
static int acpuclk_krait_set_rate(int cpu, unsigned long rate,
enum setrate_reason reason)
@@ -433,8 +475,9 @@
const struct core_speed *strt_acpu_s, *tgt_acpu_s;
const struct acpu_level *tgt;
int tgt_l2_l;
+ enum src_id prev_l2_src = NUM_SRC_ID;
struct vdd_data vdd_data;
- unsigned long flags;
+ bool skip_regulators;
int rc = 0;
if (cpu > num_possible_cpus())
@@ -478,13 +521,31 @@
rc = increase_vdd(cpu, &vdd_data, reason);
if (rc)
goto out;
+
+ prev_l2_src =
+ drv.l2_freq_tbl[drv.scalable[cpu].l2_vote].speed.src;
+ /* Vote for the L2 regulators here if necessary. */
+ if (drv.l2_freq_tbl[tgt->l2_level].speed.src == HFPLL) {
+ rc = enable_l2_regulators();
+ if (rc)
+ goto out;
+ }
}
dev_dbg(drv.dev, "Switching from ACPU%d rate %lu KHz -> %lu KHz\n",
cpu, strt_acpu_s->khz, tgt_acpu_s->khz);
+ /*
+ * If we are setting the rate as part of power collapse or in the resume
+ * path after power collapse, skip the vote for the HFPLL regulators,
+ * which are active-set-only votes that will be removed when apps enters
+ * its sleep set. This is needed to avoid voting for regulators with
+ * sleeping APIs from an atomic context.
+ */
+ skip_regulators = (reason == SETRATE_PC);
+
/* Set the new CPU speed. */
- set_speed(&drv.scalable[cpu], tgt_acpu_s);
+ set_speed(&drv.scalable[cpu], tgt_acpu_s, skip_regulators);
/*
* Update the L2 vote and apply the rate change. A spinlock is
@@ -493,15 +554,23 @@
* called from an atomic context and the driver_lock mutex is not
* acquired.
*/
- spin_lock_irqsave(&l2_lock, flags);
+ spin_lock(&l2_lock);
tgt_l2_l = compute_l2_level(&drv.scalable[cpu], tgt->l2_level);
- set_speed(&drv.scalable[L2], &drv.l2_freq_tbl[tgt_l2_l].speed);
- spin_unlock_irqrestore(&l2_lock, flags);
+ set_speed(&drv.scalable[L2],
+ &drv.l2_freq_tbl[tgt_l2_l].speed, true);
+ spin_unlock(&l2_lock);
/* Nothing else to do for power collapse or SWFI. */
if (reason == SETRATE_PC || reason == SETRATE_SWFI)
goto out;
+ /*
+ * Remove the vote for the L2 HFPLL regulators only if the L2
+ * was already on an HFPLL source.
+ */
+ if (prev_l2_src == HFPLL)
+ disable_l2_regulators();
+
/* Update bus bandwith request. */
set_bus_bw(drv.l2_freq_tbl[tgt_l2_l].bw_level);
@@ -663,6 +732,14 @@
goto err_core_conf;
}
+ /*
+ * Increment the L2 HFPLL regulator refcount if _this_ CPU's frequency
+ * requires a corresponding target L2 frequency that needs the L2 to
+ * run off of an HFPLL.
+ */
+ if (drv.l2_freq_tbl[acpu_level->l2_level].speed.src == HFPLL)
+ l2_vreg_count++;
+
return 0;
err_core_conf:
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index cb03d4b..fc44b18 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -479,6 +479,12 @@
.pull = GPIOMUX_PULL_NONE,
};
+static struct gpiomux_setting gsbi6_spi_cfg = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_16MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
static struct gpiomux_setting sx150x_suspended_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_8MA,
@@ -1514,6 +1520,33 @@
},
};
+static struct msm_gpiomux_config mpq8064_gsbi6_spi_configs[] __initdata = {
+ {
+ .gpio = 17, /* GSBI6_0 SPI CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi6_spi_cfg,
+ },
+ },
+ {
+ .gpio = 16, /* GSBI6_1 SPI CS */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi6_spi_cfg,
+ },
+ },
+ {
+ .gpio = 15, /* GSBI6_2 SPI MISO */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi6_spi_cfg,
+ },
+ },
+ {
+ .gpio = 14, /* GSBI6_3 SPI_MOSI */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi6_spi_cfg,
+ },
+ },
+};
+
void __init apq8064_init_gpiomux(void)
{
int rc;
@@ -1630,10 +1663,14 @@
msm_gpiomux_install(apq8064_mhl_configs,
ARRAY_SIZE(apq8064_mhl_configs));
- if (machine_is_mpq8064_cdp())
+ if (machine_is_mpq8064_cdp()) {
msm_gpiomux_install(mpq8064_ir_configs,
ARRAY_SIZE(mpq8064_ir_configs));
+ msm_gpiomux_install(mpq8064_gsbi6_spi_configs,
+ ARRAY_SIZE(mpq8064_gsbi6_spi_configs));
+ }
+
#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
msm_gpiomux_install(apq8064_sdc2_configs,
ARRAY_SIZE(apq8064_sdc2_configs));
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index fad7092..f35ae6b 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -281,8 +281,11 @@
if (SOCINFO_VERSION_MAJOR(version) == 2) {
kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 2, 0, 2);
} else {
+ /* The bootloader has started returning 1.2 for chips that
+ are either 1.1 or 1.2. To handle that and default any
+ future revisions to this path, check for minor version >=1 */
if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
- (SOCINFO_VERSION_MINOR(version) == 1))
+ (SOCINFO_VERSION_MINOR(version) >= 1))
kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 2, 0, 1);
else
kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 2, 0, 0);
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index e64a672..c973bd5 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -143,6 +143,7 @@
static struct pm8xxx_gpio_init pm8921_mpq8064_hrd_gpios[] __initdata = {
PM8921_GPIO_OUTPUT(37, 0, LOW), /* MUX1_SEL */
+ PM8921_GPIO_INPUT(40, PM_GPIO_PULL_UP_30), /* irq for sx150 exp2 */
};
static struct pm8xxx_gpio_init touchscreen_gpios[] __initdata = {
@@ -512,4 +513,7 @@
} else if (machine_is_apq8064_cdp()) {
apq8064_pm8921_chg_pdata.has_dc_supply = true;
}
+
+ if (!machine_is_apq8064_mtp() && !machine_is_apq8064_liquid())
+ apq8064_pm8921_chg_pdata.battery_less_hardware = 1;
}
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index 379d7ae..28f7f63 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -383,6 +383,14 @@
apq8064_sdc3_pdata->pin_data->pad_data->\
drv->on[i].val = GPIO_CFG_10MA;
}
+ if (machine_is_mpq8064_hrd() || machine_is_mpq8064_dtv()) {
+ apq8064_sdc3_pdata->pin_data->pad_data->\
+ drv->on[0].val = GPIO_CFG_16MA;
+ apq8064_sdc3_pdata->pin_data->pad_data->\
+ drv->on[1].val = GPIO_CFG_10MA;
+ apq8064_sdc3_pdata->pin_data->pad_data->\
+ drv->on[2].val = GPIO_CFG_10MA;
+ }
apq8064_add_sdcc(3, apq8064_sdc3_pdata);
}
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 9e5e4f5..c6bcb6b 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -42,6 +42,7 @@
#include <asm/hardware/gic.h>
#include <asm/mach/mmc.h>
#include <linux/platform_data/qcom_wcnss_device.h>
+#include <linux/ci-bridge-spi.h>
#include <mach/board.h>
#include <mach/msm_iomap.h>
@@ -2401,6 +2402,7 @@
static struct platform_device *common_mpq_devices[] __initdata = {
&mpq_cpudai_sec_i2s_rx,
&mpq_cpudai_mi2s_tx,
+ &mpq_cpudai_pseudo,
};
static struct platform_device *common_i2s_devices[] __initdata = {
@@ -2693,12 +2695,22 @@
&msm8064_device_vcap,
#endif
&rc_input_loopback_pdev,
+ &mpq8064_device_qup_spi_gsbi6,
};
static struct msm_spi_platform_data apq8064_qup_spi_gsbi5_pdata = {
.max_clock_speed = 1100000,
};
+static struct msm_spi_platform_data mpq8064_qup_spi_gsbi6_pdata = {
+ .max_clock_speed = 1100000,
+};
+
+static struct ci_bridge_platform_data mpq8064_ci_bridge_pdata = {
+ .reset_pin = 260,
+ .interrupt_pin = 261,
+};
+
#define KS8851_IRQ_GPIO 43
static struct spi_board_info spi_board_info[] __initdata = {
@@ -2716,6 +2728,17 @@
.bus_num = 0,
.chip_select = 3,
.mode = SPI_MODE_0,
+ }
+};
+
+static struct spi_board_info mpq8064_spi_board_info[] __initdata = {
+ {
+ .modalias = "ci_bridge_spi",
+ .max_speed_hz = 1000000,
+ .bus_num = 1,
+ .chip_select = 0,
+ .mode = SPI_MODE_0,
+ .platform_data = &mpq8064_ci_bridge_pdata,
},
};
@@ -2945,6 +2968,83 @@
},
};
+#define MPQ_HRD_HOME_GPIO SX150X_EXP2_GPIO_BASE
+#define MPQ_HRD_VOL_UP_GPIO (SX150X_EXP2_GPIO_BASE + 1)
+#define MPQ_HRD_VOL_DOWN_GPIO (SX150X_EXP2_GPIO_BASE + 2)
+#define MPQ_HRD_RIGHT_GPIO (SX150X_EXP2_GPIO_BASE + 3)
+#define MPQ_HRD_LEFT_GPIO (SX150X_EXP2_GPIO_BASE + 4)
+#define MPQ_HRD_ENTER_GPIO (SX150X_EXP2_GPIO_BASE + 5)
+
+static struct gpio_keys_button mpq_hrd_keys[] = {
+ {
+ .code = KEY_HOME,
+ .gpio = MPQ_HRD_HOME_GPIO,
+ .desc = "home_key",
+ .active_low = 1,
+ .type = EV_KEY,
+ .wakeup = 1,
+ .debounce_interval = 15,
+ },
+ {
+ .code = KEY_VOLUMEUP,
+ .gpio = MPQ_HRD_VOL_UP_GPIO,
+ .desc = "volume_up_key",
+ .active_low = 1,
+ .type = EV_KEY,
+ .wakeup = 1,
+ .debounce_interval = 15,
+ },
+ {
+ .code = KEY_VOLUMEDOWN,
+ .gpio = MPQ_HRD_VOL_DOWN_GPIO,
+ .desc = "volume_down_key",
+ .active_low = 1,
+ .type = EV_KEY,
+ .wakeup = 1,
+ .debounce_interval = 15,
+ },
+ {
+ .code = KEY_RIGHT,
+ .gpio = MPQ_HRD_RIGHT_GPIO,
+ .desc = "right_key",
+ .active_low = 1,
+ .type = EV_KEY,
+ .wakeup = 1,
+ .debounce_interval = 15,
+ },
+ {
+ .code = KEY_LEFT,
+ .gpio = MPQ_HRD_LEFT_GPIO,
+ .desc = "left_key",
+ .active_low = 1,
+ .type = EV_KEY,
+ .wakeup = 1,
+ .debounce_interval = 15,
+ },
+ {
+ .code = KEY_ENTER,
+ .gpio = MPQ_HRD_ENTER_GPIO,
+ .desc = "enter_key",
+ .active_low = 1,
+ .type = EV_KEY,
+ .wakeup = 1,
+ .debounce_interval = 15,
+ },
+};
+
+static struct gpio_keys_platform_data mpq_hrd_keys_pdata = {
+ .buttons = mpq_hrd_keys,
+ .nbuttons = ARRAY_SIZE(mpq_hrd_keys),
+};
+
+static struct platform_device mpq_hrd_keys_pdev = {
+ .name = "gpio-keys",
+ .id = -1,
+ .dev = {
+ .platform_data = &mpq_hrd_keys_pdata,
+ },
+};
+
static struct gpio_keys_button mpq_keys[] = {
{
.code = KEY_VOLUMEDOWN,
@@ -3300,6 +3400,15 @@
msm_clock_init(&apq8064_clock_init_data);
apq8064_init_gpiomux();
apq8064_i2c_init();
+
+ /* configure sx150x parameters for HRD */
+ if (machine_is_mpq8064_hrd()) {
+ mpq8064_sx150x_pdata[SX150X_EXP2].irq_summary =
+ PM8921_GPIO_IRQ(PM8921_IRQ_BASE, 40);
+ mpq8064_sx150x_pdata[SX150X_EXP2].io_pullup_ena = 0xff;
+ mpq8064_sx150x_pdata[SX150X_EXP2].io_pulldn_ena = 0x00;
+ }
+
register_i2c_devices();
apq8064_device_qup_spi_gsbi5.dev.platform_data =
@@ -3404,8 +3513,14 @@
msm_rpmrs_levels[0].latency_us;
enable_avc_i2c_bus();
msm_rotator_set_split_iommu_domain();
+
+ mpq8064_device_qup_spi_gsbi6.dev.platform_data =
+ &mpq8064_qup_spi_gsbi6_pdata;
+
platform_add_devices(mpq_devices, ARRAY_SIZE(mpq_devices));
mpq8064_pcie_init();
+ spi_register_board_info(mpq8064_spi_board_info,
+ ARRAY_SIZE(mpq8064_spi_board_info));
} else {
ethernet_init();
msm_rotator_set_split_iommu_domain();
@@ -3446,7 +3561,8 @@
if (machine_is_mpq8064_cdp()) {
platform_device_register(&mpq_gpio_keys_pdev);
platform_device_register(&mpq_keypad_device);
- }
+ } else if (machine_is_mpq8064_hrd())
+ platform_device_register(&mpq_hrd_keys_pdev);
}
MACHINE_START(APQ8064_CDP, "QCT APQ8064 CDP")
diff --git a/arch/arm/mach-msm/board-8092.c b/arch/arm/mach-msm/board-8092.c
index 527de41..3e31f68 100644
--- a/arch/arm/mach-msm/board-8092.c
+++ b/arch/arm/mach-msm/board-8092.c
@@ -18,7 +18,6 @@
#include <linux/of_fdt.h>
#include <linux/of_irq.h>
#include <asm/hardware/gic.h>
-#include <asm/arch_timer.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
#include <mach/socinfo.h>
@@ -30,15 +29,9 @@
#include <linux/irq.h>
#include <linux/irqdomain.h>
+#include "board-dt.h"
#include "clock.h"
-static struct of_device_id irq_match[] __initdata = {
- { .compatible = "qcom,msm-qgic2", .data = gic_of_init, },
- { .compatible = "qcom,msm-gpio", .data = msm_gpio_of_init, },
- { .compatible = "qcom,spmi-pmic-arb", .data = qpnpint_of_init, },
- {}
-};
-
static struct clk_lookup msm_clocks_dummy[] = {
CLK_DUMMY("core_clk", BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
@@ -81,26 +74,7 @@
msm_reserve();
}
-void __init mpq8092_init_irq(void)
-{
- of_irq_init(irq_match);
-}
-
-static void __init mpq8092_dt_timer_init(void)
-{
- arch_timer_of_register();
-}
-
-static struct sys_timer mpq8092_dt_timer = {
- .init = mpq8092_dt_timer_init
-};
-
-static void __init mpq8092_dt_init_irq(void)
-{
- mpq8092_init_irq();
-}
-
-static void __init mpq8092_dt_map_io(void)
+static void __init mpq8092_map_io(void)
{
msm_map_mpq8092_io();
if (socinfo_init() < 0)
@@ -120,18 +94,12 @@
{}
};
-static void __init mpq8092_init(struct of_dev_auxdata **adata)
+static void __init mpq8092_init(void)
{
+ struct of_dev_auxdata *adata = mpq8092_auxdata_lookup;
+
mpq8092_init_gpiomux();
- *adata = mpq8092_auxdata_lookup;
msm_clock_init(&mpq8092_clock_init_data);
-}
-
-static void __init mpq8092_dt_init(void)
-{
- struct of_dev_auxdata *adata = NULL;
-
- mpq8092_init(&adata);
of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
}
@@ -140,12 +108,12 @@
NULL
};
-DT_MACHINE_START(MSM_DT, "Qualcomm MSM (Flattened Device Tree)")
- .map_io = mpq8092_dt_map_io,
- .init_irq = mpq8092_dt_init_irq,
- .init_machine = mpq8092_dt_init,
+DT_MACHINE_START(MSM8092_DT, "Qualcomm MSM 8092 (Flattened Device Tree)")
+ .map_io = mpq8092_map_io,
+ .init_irq = msm_dt_init_irq_nompm,
+ .init_machine = mpq8092_init,
.handle_irq = gic_handle_irq,
- .timer = &mpq8092_dt_timer,
+ .timer = &msm_dt_timer,
.dt_compat = mpq8092_dt_match,
.reserve = mpq8092_dt_reserve,
.init_very_early = mpq8092_early_memory,
diff --git a/arch/arm/mach-msm/board-8910.c b/arch/arm/mach-msm/board-8910.c
index 9afc05e..eaf146b 100644
--- a/arch/arm/mach-msm/board-8910.c
+++ b/arch/arm/mach-msm/board-8910.c
@@ -37,6 +37,7 @@
#include <mach/socinfo.h>
#include <mach/board.h>
#include <mach/clk-provider.h>
+#include "board-dt.h"
#include "clock.h"
static struct clk_lookup msm_clocks_dummy[] = {
@@ -47,6 +48,9 @@
CLK_DUMMY("iface_clk", NULL, "f9824000.qcom,sdcc", OFF),
CLK_DUMMY("core_clk", NULL, "f9824000.qcom,sdcc", OFF),
CLK_DUMMY("bus_clk", NULL, "f9824000.qcom,sdcc", OFF),
+ CLK_DUMMY("iface_clk", NULL, "f98a4000.qcom,sdcc", OFF),
+ CLK_DUMMY("core_clk", NULL, "f98a4000.qcom,sdcc", OFF),
+ CLK_DUMMY("bus_clk", NULL, "f98a4000.qcom,sdcc", OFF),
};
struct clock_init_data msm_dummy_clock_init_data __initdata = {
@@ -54,26 +58,6 @@
.size = ARRAY_SIZE(msm_clocks_dummy),
};
-static struct of_device_id irq_match[] __initdata = {
- { .compatible = "qcom,msm-qgic2", .data = gic_of_init, },
- { .compatible = "qcom,msm-gpio", .data = msm_gpio_of_init, },
- {},
-};
-
-static void __init msm8910_dt_timer_init(void)
-{
- arch_timer_of_register();
-}
-
-static struct sys_timer msm8910_dt_timer = {
- .init = msm8910_dt_timer_init
-};
-
-void __init msm8910_init_irq(void)
-{
- of_irq_init(irq_match);
-}
-
void __init msm8910_init(void)
{
msm_clock_init(&msm_dummy_clock_init_data);
@@ -91,9 +75,9 @@
DT_MACHINE_START(MSM8910_DT, "Qualcomm MSM 8910 (Flattened Device Tree)")
.map_io = msm_map_msm8910_io,
- .init_irq = msm8910_init_irq,
+ .init_irq = msm_dt_init_irq_nompm,
.init_machine = msm8910_init,
.handle_irq = gic_handle_irq,
- .timer = &msm8910_dt_timer,
+ .timer = &msm_dt_timer,
.dt_compat = msm8910_dt_match,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-8930-gpu.c b/arch/arm/mach-msm/board-8930-gpu.c
index 99a5a34..578c665 100644
--- a/arch/arm/mach-msm/board-8930-gpu.c
+++ b/arch/arm/mach-msm/board-8930-gpu.c
@@ -163,10 +163,18 @@
{
unsigned int version = socinfo_get_version();
+ /* Set the turbo speed for the AA and AB respectively */
+
if (cpu_is_msm8930aa())
kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 450000000;
+ else if (cpu_is_msm8930ab())
+ kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 500000000;
- if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
+ /* Set up the chip ID based on the SoC version */
+
+ if (cpu_is_msm8930ab())
+ kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 0, 5, 3);
+ else if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
(SOCINFO_VERSION_MINOR(version) == 2))
kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 0, 5, 2);
else
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 8687b2a..0c7666b 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -596,4 +596,7 @@
else if (machine_is_msm8930_cdp())
pm8921_chg_pdata.has_dc_supply = true;
}
+
+ if (!machine_is_msm8930_mtp())
+ pm8921_chg_pdata.battery_less_hardware = 1;
}
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8038.c b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
index 16a82b4..727c4c6 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8038.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
@@ -97,6 +97,8 @@
REGULATOR_SUPPLY("CDC_VDDA_RX", "sitar1p1-slim"),
REGULATOR_SUPPLY("vddp", "0-0048"),
REGULATOR_SUPPLY("mhl_iovcc18", "0-0039"),
+ REGULATOR_SUPPLY("vdd-io", "spi0.0"),
+ REGULATOR_SUPPLY("vdd-phy", "spi0.0"),
};
VREG_CONSUMERS(L12) = {
REGULATOR_SUPPLY("8038_l12", NULL),
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8917.c b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
index 8898b50..33e38ab 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8917.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
@@ -196,6 +196,8 @@
REGULATOR_SUPPLY("mhl_iovcc18", "0-0039"),
REGULATOR_SUPPLY("CDC_VDD_CP", "sitar-slim"),
REGULATOR_SUPPLY("CDC_VDD_CP", "sitar1p1-slim"),
+ REGULATOR_SUPPLY("vdd-io", "spi0.0"),
+ REGULATOR_SUPPLY("vdd-phy", "spi0.0"),
};
VREG_CONSUMERS(S5) = {
REGULATOR_SUPPLY("8917_s5", NULL),
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index d8a260b..9efedb1 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -612,4 +612,8 @@
if (machine_is_msm8960_fluid())
pm8921_bms_pdata.rconn_mohm = 20;
+
+ if (!machine_is_msm8960_fluid() && !machine_is_msm8960_liquid()
+ && !machine_is_msm8960_fluid())
+ pm8921_chg_pdata.battery_less_hardware = 1;
}
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 4a78e31..ce2531b 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -3216,6 +3216,17 @@
msm_tsens_early_init(&msm_tsens_pdata);
}
+static void __init msm8960_reset_spm_avs(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(msm_spm_data); i++) {
+ struct msm_spm_platform_data *pdata = &msm_spm_data[i];
+ pdata->reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0;
+ pdata->reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0;
+ }
+}
+
static void __init msm8960_cdp_init(void)
{
if (meminfo_init(SYS_MEMORY, SZ_256M) < 0)
@@ -3269,10 +3280,20 @@
msm_isa1200_board_info[0].platform_data = &isa1200_1_pdata;
msm8960_i2c_init();
msm8960_gfx_init();
+
+ if (cpu_is_msm8960ab())
+ msm8960_reset_spm_avs();
msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
msm_spm_l2_init(msm_spm_l2_data);
+
msm8960_init_buses();
- platform_add_devices(msm8960_footswitch, msm8960_num_footswitch);
+ if (cpu_is_msm8960ab()) {
+ platform_add_devices(msm8960ab_footswitch,
+ msm8960ab_num_footswitch);
+ } else {
+ platform_add_devices(msm8960_footswitch,
+ msm8960_num_footswitch);
+ }
if (machine_is_msm8960_liquid())
platform_device_register(&msm8960_device_ext_3p3v_vreg);
if (machine_is_msm8960_cdp())
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 7480437..19fb222 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -198,7 +198,7 @@
.edge = SMD_APPS_RPM,
.smd_int.irq_name = "rpm_smd_in",
- .smd_int.flags = IRQF_TRIGGER_RISING,
+ .smd_int.flags = IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND,
.smd_int.irq_id = -1,
.smd_int.device_name = "smd_dev",
.smd_int.dev_id = 0,
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 49f2561..5c7eebe 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -21,11 +21,8 @@
#include <linux/of_irq.h>
#include <linux/memory.h>
#include <asm/mach/map.h>
-#include <asm/hardware/cache-l2x0.h>
#include <asm/hardware/gic.h>
-#include <asm/arch_timer.h>
#include <asm/mach/arch.h>
-#include <asm/mach/time.h>
#include <mach/socinfo.h>
#include <mach/board.h>
#include <mach/restart.h>
@@ -35,19 +32,15 @@
#include <mach/msm_memtypes.h>
#include <mach/msm_iomap.h>
#include <mach/msm_smd.h>
-#include <mach/scm.h>
#include <mach/rpm-smd.h>
#include <mach/rpm-regulator-smd.h>
-#include <mach/mpm.h>
+#include "board-dt.h"
#include "clock.h"
#include "modem_notifier.h"
#include "lpm_resources.h"
#include "spm.h"
#define MSM_KERNEL_EBI_SIZE 0x51000
-#define SCM_SVC_L2CC_PL310 16
-#define L2CC_PL310_CTRL_ID 1
-#define L2CC_PL310_ON 1
static struct memtype_reserve msm9625_reserve_table[] __initdata = {
[MEMTYPE_SMI] = {
@@ -76,10 +69,6 @@
.paddr_to_memtype = msm9625_paddr_to_memtype,
};
-#define L2CC_AUX_CTRL ((0x1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) | \
- (0x2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | \
- (0x1 << L2X0_AUX_CTRL_EVNT_MON_BUS_EN_SHIFT))
-
static struct clk_lookup msm_clocks_dummy[] = {
CLK_DUMMY("core_clk", BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
@@ -103,13 +92,6 @@
.size = ARRAY_SIZE(msm_clocks_dummy),
};
-static struct of_device_id irq_match[] __initdata = {
- { .compatible = "qcom,msm-qgic2", .data = gic_of_init, },
- { .compatible = "qcom,msm-gpio", .data = msm_gpio_of_init, },
- { .compatible = "qcom,spmi-pmic-arb", .data = qpnpint_of_init, },
- {}
-};
-
static const char *msm9625_dt_match[] __initconst = {
"qcom,msm9625",
NULL
@@ -129,34 +111,6 @@
{}
};
-static struct of_device_id mpm_match[] __initdata = {
- {.compatible = "qcom,mpm-v2", },
- {},
-};
-
-void __init msm9625_init_irq(void)
-{
- struct device_node *node;
- scm_call_atomic1(SCM_SVC_L2CC_PL310, L2CC_PL310_CTRL_ID, L2CC_PL310_ON);
- l2x0_of_init(0, ~0UL);
- of_irq_init(irq_match);
- node = of_find_matching_node(NULL, mpm_match);
-
- WARN_ON(!node);
-
- if (node)
- of_mpm_init(node);
-}
-
-static void __init msm_dt_timer_init(void)
-{
- arch_timer_of_register();
-}
-
-static struct sys_timer msm_dt_timer = {
- .init = msm_dt_timer_init
-};
-
static void __init msm9625_early_memory(void)
{
reserve_info = &msm9625_reserve_info;
@@ -331,9 +285,9 @@
msm9625_add_drivers();
}
-DT_MACHINE_START(MSM_DT, "Qualcomm MSM (Flattened Device Tree)")
+DT_MACHINE_START(MSM9625_DT, "Qualcomm MSM 9625 (Flattened Device Tree)")
.map_io = msm_map_msm9625_io,
- .init_irq = msm9625_init_irq,
+ .init_irq = msm_dt_init_irq_l2x0,
.init_machine = msm9625_init,
.handle_irq = gic_handle_irq,
.timer = &msm_dt_timer,
diff --git a/arch/arm/mach-msm/board-dt.c b/arch/arm/mach-msm/board-dt.c
index 3654de8..74b0d0d 100644
--- a/arch/arm/mach-msm/board-dt.c
+++ b/arch/arm/mach-msm/board-dt.c
@@ -17,12 +17,18 @@
#include <linux/mfd/wcd9xxx/core.h>
#include <asm/arch_timer.h>
#include <asm/mach/time.h>
+#include <asm/hardware/cache-l2x0.h>
#include <asm/hardware/gic.h>
#include <mach/mpm.h>
#include <mach/qpnp-int.h>
+#include <mach/scm.h>
#include "board-dt.h"
+#define SCM_SVC_L2CC_PL310 16
+#define L2CC_PL310_CTRL_ID 1
+#define L2CC_PL310_ON 1
+
static void __init msm_dt_timer_init(void)
{
arch_timer_of_register();
@@ -62,3 +68,10 @@
{
of_irq_init(irq_match);
}
+
+void __init msm_dt_init_irq_l2x0(void)
+{
+ scm_call_atomic1(SCM_SVC_L2CC_PL310, L2CC_PL310_CTRL_ID, L2CC_PL310_ON);
+ l2x0_of_init(0, ~0UL);
+ msm_dt_init_irq();
+}
diff --git a/arch/arm/mach-msm/board-dt.h b/arch/arm/mach-msm/board-dt.h
index 16a6135..cc3e92c 100644
--- a/arch/arm/mach-msm/board-dt.h
+++ b/arch/arm/mach-msm/board-dt.h
@@ -13,3 +13,4 @@
extern struct sys_timer msm_dt_timer;
void __init msm_dt_init_irq(void);
void __init msm_dt_init_irq_nompm(void);
+void __init msm_dt_init_irq_l2x0(void);
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
index e42fe65..e1390db 100644
--- a/arch/arm/mach-msm/clock-7x30.c
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -160,7 +160,8 @@
VDD_DIG_NONE,
VDD_DIG_LOW,
VDD_DIG_NOMINAL,
- VDD_DIG_HIGH
+ VDD_DIG_HIGH,
+ VDD_DIG_NUM
};
static int set_vdd_dig(struct clk_vdd_class *vdd_class, int level)
@@ -184,15 +185,21 @@
return rc;
}
-static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig);
+static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig, VDD_DIG_NUM);
#define VDD_DIG_FMAX_MAP1(l1, f1) \
- .vdd_class = &vdd_dig, \
- .fmax[VDD_DIG_##l1] = (f1)
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
- .vdd_class = &vdd_dig, \
- .fmax[VDD_DIG_##l1] = (f1), \
- .fmax[VDD_DIG_##l2] = (f2)
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
#define PCOM_XO_DISABLE 0
#define PCOM_XO_ENABLE 1
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 934bf88..3c417c3 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -376,7 +376,8 @@
VDD_DIG_NONE,
VDD_DIG_LOW,
VDD_DIG_NOMINAL,
- VDD_DIG_HIGH
+ VDD_DIG_HIGH,
+ VDD_DIG_NUM
};
static int set_vdd_dig_8960(struct clk_vdd_class *vdd_class, int level)
@@ -391,7 +392,7 @@
vdd_uv[level], 1150000, 1);
}
-static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig_8960);
+static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig_8960, VDD_DIG_NUM);
static int rpm_vreg_dig_8930 = RPM_VREG_ID_PM8038_VDD_DIG_CORNER;
static int set_vdd_dig_8930(struct clk_vdd_class *vdd_class, int level)
@@ -409,21 +410,31 @@
}
#define VDD_DIG_FMAX_MAP1(l1, f1) \
- .vdd_class = &vdd_dig, \
- .fmax[VDD_DIG_##l1] = (f1)
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
- .vdd_class = &vdd_dig, \
- .fmax[VDD_DIG_##l1] = (f1), \
- .fmax[VDD_DIG_##l2] = (f2)
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
- .vdd_class = &vdd_dig, \
- .fmax[VDD_DIG_##l1] = (f1), \
- .fmax[VDD_DIG_##l2] = (f2), \
- .fmax[VDD_DIG_##l3] = (f3)
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ [VDD_DIG_##l3] = (f3), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
enum vdd_sr2_hdmi_pll_levels {
VDD_SR2_HDMI_PLL_OFF,
- VDD_SR2_HDMI_PLL_ON
+ VDD_SR2_HDMI_PLL_ON,
+ VDD_SR2_HDMI_PLL_NUM
};
static int set_vdd_sr2_hdmi_pll_8960(struct clk_vdd_class *vdd_class, int level)
@@ -455,7 +466,8 @@
return rc;
}
-static DEFINE_VDD_CLASS(vdd_sr2_hdmi_pll, set_vdd_sr2_hdmi_pll_8960);
+static DEFINE_VDD_CLASS(vdd_sr2_hdmi_pll, set_vdd_sr2_hdmi_pll_8960,
+ VDD_SR2_HDMI_PLL_NUM);
static int sr2_lreg_uv[] = {
[VDD_SR2_HDMI_PLL_OFF] = 0,
@@ -530,7 +542,10 @@
.rate = 1200000000,
.ops = &clk_ops_local_pll,
.vdd_class = &vdd_sr2_hdmi_pll,
- .fmax[VDD_SR2_HDMI_PLL_ON] = ULONG_MAX,
+ .fmax = (unsigned long[VDD_SR2_HDMI_PLL_NUM]) {
+ [VDD_SR2_HDMI_PLL_ON] = ULONG_MAX
+ },
+ .num_fmax = VDD_SR2_HDMI_PLL_NUM,
CLK_INIT(pll3_clk.c),
},
};
@@ -1532,7 +1547,7 @@
static CLK_SDC(sdc4_clk, 4, 3, 33000000, 67000000);
static CLK_SDC(sdc5_clk, 5, 2, 33000000, 67000000);
-static unsigned long fmax_sdc1_8064v2[MAX_VDD_LEVELS] __initdata = {
+static unsigned long fmax_sdc1_8064v2[VDD_DIG_NUM] = {
[VDD_DIG_LOW] = 100000000,
[VDD_DIG_NOMINAL] = 200000000,
};
@@ -1933,7 +1948,7 @@
},
};
-static unsigned long fmax_ce3_8064v2[MAX_VDD_LEVELS] __initdata = {
+static unsigned long fmax_ce3_8064v2[VDD_DIG_NUM] = {
[VDD_DIG_LOW] = 57000000,
[VDD_DIG_NOMINAL] = 120000000,
};
@@ -3580,25 +3595,25 @@
F_END
};
-static unsigned long fmax_gfx3d_8064ab[MAX_VDD_LEVELS] __initdata = {
+static unsigned long fmax_gfx3d_8064ab[VDD_DIG_NUM] = {
[VDD_DIG_LOW] = 128000000,
[VDD_DIG_NOMINAL] = 325000000,
[VDD_DIG_HIGH] = 450000000
};
-static unsigned long fmax_gfx3d_8064[MAX_VDD_LEVELS] __initdata = {
+static unsigned long fmax_gfx3d_8064[VDD_DIG_NUM] = {
[VDD_DIG_LOW] = 128000000,
[VDD_DIG_NOMINAL] = 325000000,
[VDD_DIG_HIGH] = 400000000
};
-static unsigned long fmax_gfx3d_8930[MAX_VDD_LEVELS] __initdata = {
+static unsigned long fmax_gfx3d_8930[VDD_DIG_NUM] = {
[VDD_DIG_LOW] = 192000000,
[VDD_DIG_NOMINAL] = 320000000,
[VDD_DIG_HIGH] = 400000000
};
-static unsigned long fmax_gfx3d_8930aa[MAX_VDD_LEVELS] __initdata = {
+static unsigned long fmax_gfx3d_8930aa[VDD_DIG_NUM] = {
[VDD_DIG_LOW] = 192000000,
[VDD_DIG_NOMINAL] = 320000000,
[VDD_DIG_HIGH] = 450000000
@@ -3750,7 +3765,7 @@
F_END
};
-static unsigned long fmax_ijpeg_8064[MAX_VDD_LEVELS] __initdata = {
+static unsigned long fmax_ijpeg_8064[VDD_DIG_NUM] = {
[VDD_DIG_LOW] = 128000000,
[VDD_DIG_NOMINAL] = 266667000,
[VDD_DIG_HIGH] = 320000000
@@ -3877,7 +3892,7 @@
F_END
};
-static unsigned long fmax_mdp_8064[MAX_VDD_LEVELS] __initdata = {
+static unsigned long fmax_mdp_8064[VDD_DIG_NUM] = {
[VDD_DIG_LOW] = 128000000,
[VDD_DIG_NOMINAL] = 266667000
};
@@ -4071,7 +4086,10 @@
.dbg_name = "hdmi_pll_clk",
.ops = &clk_ops_hdmi_pll,
.vdd_class = &vdd_sr2_hdmi_pll,
- .fmax[VDD_SR2_HDMI_PLL_ON] = ULONG_MAX,
+ .fmax = (unsigned long [VDD_SR2_HDMI_PLL_NUM]) {
+ [VDD_SR2_HDMI_PLL_ON] = ULONG_MAX,
+ },
+ .num_fmax = VDD_SR2_HDMI_PLL_NUM,
CLK_INIT(hdmi_pll_clk),
};
@@ -4103,7 +4121,7 @@
F_END
};
-static unsigned long fmax_tv_src_8064[MAX_VDD_LEVELS] __initdata = {
+static unsigned long fmax_tv_src_8064[VDD_DIG_NUM] = {
[VDD_DIG_LOW] = 74250000,
[VDD_DIG_NOMINAL] = 149000000
};
@@ -4342,7 +4360,7 @@
},
};
-static unsigned long fmax_vcodec_8064v2[MAX_VDD_LEVELS] __initdata = {
+static unsigned long fmax_vcodec_8064v2[VDD_DIG_NUM] = {
[VDD_DIG_LOW] = 100000000,
[VDD_DIG_NOMINAL] = 200000000,
[VDD_DIG_HIGH] = 266670000,
@@ -4424,7 +4442,7 @@
F_END
};
-static unsigned long fmax_vfe_8064[MAX_VDD_LEVELS] __initdata = {
+static unsigned long fmax_vfe_8064[VDD_DIG_NUM] = {
[VDD_DIG_LOW] = 128000000,
[VDD_DIG_NOMINAL] = 266667000,
[VDD_DIG_HIGH] = 320000000
@@ -5289,7 +5307,7 @@
CLK_LOOKUP("core_clk", gsbi4_qup_clk.c, "qup_i2c.4"),
CLK_LOOKUP("core_clk", gsbi5_qup_clk.c, "spi_qsd.0"),
CLK_LOOKUP("core_clk", gsbi5_qup_clk.c, "qup_i2c.5"),
- CLK_LOOKUP("core_clk", gsbi6_qup_clk.c, ""),
+ CLK_LOOKUP("core_clk", gsbi6_qup_clk.c, "spi_qsd.1"),
CLK_LOOKUP("core_clk", gsbi7_qup_clk.c, ""),
CLK_LOOKUP("core_clk", pdm_clk.c, ""),
CLK_LOOKUP("mem_clk", pmem_clk.c, "msm_sps"),
@@ -5332,6 +5350,7 @@
CLK_LOOKUP("iface_clk", gsbi5_p_clk.c, "spi_qsd.0"),
CLK_LOOKUP("iface_clk", gsbi5_p_clk.c, "qup_i2c.5"),
CLK_LOOKUP("iface_clk", gsbi6_p_clk.c, "msm_serial_hs.0"),
+ CLK_LOOKUP("iface_clk", gsbi6_p_clk.c, "spi_qsd.1"),
CLK_LOOKUP("iface_clk", gsbi7_p_clk.c, "msm_serial_hsl.0"),
CLK_LOOKUP("ref_clk", tsif_ref_clk.c, "msm_tspp.0"),
CLK_LOOKUP("iface_clk", tsif_p_clk.c, "msm_tspp.0"),
@@ -6565,37 +6584,25 @@
*/
if (cpu_is_apq8064()) {
gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8064;
-
- memcpy(gfx3d_clk.c.fmax, fmax_gfx3d_8064,
- sizeof(gfx3d_clk.c.fmax));
+ gfx3d_clk.c.fmax = fmax_gfx3d_8064;
}
if (cpu_is_apq8064ab()) {
gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8064;
-
- memcpy(gfx3d_clk.c.fmax, fmax_gfx3d_8064ab,
- sizeof(gfx3d_clk.c.fmax));
+ gfx3d_clk.c.fmax = fmax_gfx3d_8064ab;
}
if ((cpu_is_apq8064() &&
SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) ||
cpu_is_apq8064ab()) {
- memcpy(vcodec_clk.c.fmax, fmax_vcodec_8064v2,
- sizeof(vcodec_clk.c.fmax));
- memcpy(ce3_src_clk.c.fmax, fmax_ce3_8064v2,
- sizeof(ce3_src_clk.c.fmax));
- memcpy(sdc1_clk.c.fmax, fmax_sdc1_8064v2,
- sizeof(sdc1_clk.c.fmax));
+ vcodec_clk.c.fmax = fmax_vcodec_8064v2;
+ ce3_src_clk.c.fmax = fmax_ce3_8064v2;
+ sdc1_clk.c.fmax = fmax_sdc1_8064v2;
}
if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
- memcpy(ijpeg_clk.c.fmax, fmax_ijpeg_8064,
- sizeof(ijpeg_clk.c.fmax));
- memcpy(mdp_clk.c.fmax, fmax_mdp_8064,
- sizeof(ijpeg_clk.c.fmax));
- memcpy(tv_src_clk.c.fmax, fmax_tv_src_8064,
- sizeof(tv_src_clk.c.fmax));
- memcpy(vfe_clk.c.fmax, fmax_vfe_8064,
- sizeof(vfe_clk.c.fmax));
-
+ ijpeg_clk.c.fmax = fmax_ijpeg_8064;
+ mdp_clk.c.fmax = fmax_mdp_8064;
+ tv_src_clk.c.fmax = fmax_tv_src_8064;
+ vfe_clk.c.fmax = fmax_vfe_8064;
gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
}
@@ -6604,11 +6611,9 @@
* clocks which differ between 8960 and 8930.
*/
if (cpu_is_msm8930() || cpu_is_msm8627()) {
- memcpy(gfx3d_clk.c.fmax, fmax_gfx3d_8930,
- sizeof(gfx3d_clk.c.fmax));
+ gfx3d_clk.c.fmax = fmax_gfx3d_8930;
} else if (cpu_is_msm8930aa()) {
- memcpy(gfx3d_clk.c.fmax, fmax_gfx3d_8930aa,
- sizeof(gfx3d_clk.c.fmax));
+ gfx3d_clk.c.fmax = fmax_gfx3d_8930aa;
}
if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8930;
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 246ceaf..76b8abf 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -588,23 +588,33 @@
}
#define VDD_DIG_FMAX_MAP1(l1, f1) \
- .vdd_class = &vdd_dig, \
- .fmax[VDD_DIG_##l1] = (f1)
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
- .vdd_class = &vdd_dig, \
- .fmax[VDD_DIG_##l1] = (f1), \
- .fmax[VDD_DIG_##l2] = (f2)
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
- .vdd_class = &vdd_dig, \
- .fmax[VDD_DIG_##l1] = (f1), \
- .fmax[VDD_DIG_##l2] = (f2), \
- .fmax[VDD_DIG_##l3] = (f3)
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ [VDD_DIG_##l3] = (f3), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
enum vdd_dig_levels {
VDD_DIG_NONE,
VDD_DIG_LOW,
VDD_DIG_NOMINAL,
- VDD_DIG_HIGH
+ VDD_DIG_HIGH,
+ VDD_DIG_NUM
};
static const int vdd_corner[] = {
@@ -622,7 +632,7 @@
RPM_REGULATOR_CORNER_SUPER_TURBO);
}
-static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig);
+static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig, VDD_DIG_NUM);
#define RPM_MISC_CLK_TYPE 0x306b6c63
#define RPM_BUS_CLK_TYPE 0x316b6c63
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index bc4bb2e..3816b54 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -268,7 +268,8 @@
VDD_DIG_NONE,
VDD_DIG_LOW,
VDD_DIG_NOMINAL,
- VDD_DIG_HIGH
+ VDD_DIG_HIGH,
+ VDD_DIG_NUM
};
static int set_vdd_dig(struct clk_vdd_class *vdd_class, int level)
@@ -284,20 +285,29 @@
vdd_uv[level], 1200000, 1);
}
-static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig);
+static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig, VDD_DIG_NUM);
#define VDD_DIG_FMAX_MAP1(l1, f1) \
- .vdd_class = &vdd_dig, \
- .fmax[VDD_DIG_##l1] = (f1)
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
- .vdd_class = &vdd_dig, \
- .fmax[VDD_DIG_##l1] = (f1), \
- .fmax[VDD_DIG_##l2] = (f2)
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
- .vdd_class = &vdd_dig, \
- .fmax[VDD_DIG_##l1] = (f1), \
- .fmax[VDD_DIG_##l2] = (f2), \
- .fmax[VDD_DIG_##l3] = (f3)
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ [VDD_DIG_##l3] = (f3), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
DEFINE_CLK_RPM_BRANCH(pxo_clk, pxo_a_clk, PXO, 27000000);
DEFINE_CLK_RPM_BRANCH(cxo_clk, cxo_a_clk, CXO, 19200000);
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 035ef5c..338361b 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -182,7 +182,8 @@
VDD_DIG_NONE,
VDD_DIG_LOW,
VDD_DIG_NOMINAL,
- VDD_DIG_HIGH
+ VDD_DIG_HIGH,
+ VDD_DIG_NUM
};
static int set_vdd_dig(struct clk_vdd_class *vdd_class, int level)
@@ -198,15 +199,21 @@
RPM_VREG_VOTER3, vdd_corner[level], RPM_VREG_CORNER_HIGH, 1);
}
-static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig);
+static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig, VDD_DIG_NUM);
#define VDD_DIG_FMAX_MAP1(l1, f1) \
- .vdd_class = &vdd_dig, \
- .fmax[VDD_DIG_##l1] = (f1)
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
- .vdd_class = &vdd_dig, \
- .fmax[VDD_DIG_##l1] = (f1), \
- .fmax[VDD_DIG_##l2] = (f2)
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
/*
* Clock Descriptions
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index fb4f32a..b9362cf 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -291,23 +291,33 @@
}
#define VDD_DIG_FMAX_MAP1(l1, f1) \
- .vdd_class = &vdd_dig, \
- .fmax[VDD_DIG_##l1] = (f1)
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
- .vdd_class = &vdd_dig, \
- .fmax[VDD_DIG_##l1] = (f1), \
- .fmax[VDD_DIG_##l2] = (f2)
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
- .vdd_class = &vdd_dig, \
- .fmax[VDD_DIG_##l1] = (f1), \
- .fmax[VDD_DIG_##l2] = (f2), \
- .fmax[VDD_DIG_##l3] = (f3)
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ [VDD_DIG_##l3] = (f3), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
enum vdd_dig_levels {
VDD_DIG_NONE,
VDD_DIG_LOW,
VDD_DIG_NOMINAL,
- VDD_DIG_HIGH
+ VDD_DIG_HIGH,
+ VDD_DIG_NUM
};
static const int vdd_corner[] = {
@@ -325,7 +335,7 @@
RPM_REGULATOR_CORNER_SUPER_TURBO);
}
-static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig);
+static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig, VDD_DIG_NUM);
/* TODO: Needs to confirm the below values */
#define RPM_MISC_CLK_TYPE 0x306b6c63
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
index 8bd4433..489d623 100644
--- a/arch/arm/mach-msm/clock-debug.c
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -157,7 +157,7 @@
clock->dbg_name, clock->rate);
return 0;
}
- for (level = 0; level < ARRAY_SIZE(clock->fmax); level++) {
+ for (level = 0; level < clock->num_fmax; level++) {
if (vdd_level == level)
seq_printf(m, "[%lu] ", clock->fmax[level]);
else
@@ -189,7 +189,7 @@
if (!clock->vdd_class) {
fmax = INT_MAX;
} else {
- for (level = 0; level < ARRAY_SIZE(clock->fmax); level++)
+ for (level = 0; level < clock->num_fmax; level++)
if (clock->fmax[level])
fmax = clock->fmax[level];
}
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 5100980..e9dd974 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -37,11 +37,11 @@
{
int level;
- for (level = 0; level < ARRAY_SIZE(clk->fmax); level++)
+ for (level = 0; level < clk->num_fmax; level++)
if (rate <= clk->fmax[level])
break;
- if (level == ARRAY_SIZE(clk->fmax)) {
+ if (level == clk->num_fmax) {
pr_err("Rate %lu for %s is greater than highest Fmax\n", rate,
clk->dbg_name);
return -EINVAL;
@@ -55,7 +55,7 @@
{
int level, rc;
- for (level = ARRAY_SIZE(vdd_class->level_votes)-1; level > 0; level--)
+ for (level = vdd_class->num_levels-1; level > 0; level--)
if (vdd_class->level_votes[level])
break;
@@ -74,6 +74,9 @@
{
int rc;
+ if (level >= vdd_class->num_levels)
+ return -EINVAL;
+
mutex_lock(&vdd_class->lock);
vdd_class->level_votes[level]++;
rc = update_vdd(vdd_class);
@@ -89,6 +92,9 @@
{
int rc = 0;
+ if (level >= vdd_class->num_levels)
+ return -EINVAL;
+
mutex_lock(&vdd_class->lock);
if (WARN(!vdd_class->level_votes[level],
"Reference counts are incorrect for %s level %d\n",
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index d727c54..fbfa036 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -373,6 +373,58 @@
.resource = resources_qup_spi_gsbi5,
};
+static struct resource resources_qup_spi_gsbi6[] = {
+ {
+ .name = "spi_base",
+ .start = MSM_GSBI6_QUP_PHYS,
+ .end = MSM_GSBI6_QUP_PHYS + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "gsbi_base",
+ .start = MSM_GSBI6_PHYS,
+ .end = MSM_GSBI6_PHYS + 4 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "spi_irq_in",
+ .start = GSBI6_QUP_IRQ,
+ .end = GSBI6_QUP_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "spi_clk",
+ .start = 17,
+ .end = 17,
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .name = "spi_miso",
+ .start = 15,
+ .end = 15,
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .name = "spi_mosi",
+ .start = 14,
+ .end = 14,
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .name = "spi_cs",
+ .start = 16,
+ .end = 16,
+ .flags = IORESOURCE_IO,
+ }
+};
+
+struct platform_device mpq8064_device_qup_spi_gsbi6 = {
+ .name = "spi_qsd",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(resources_qup_spi_gsbi6),
+ .resource = resources_qup_spi_gsbi6,
+};
+
static struct resource resources_qup_i2c_gsbi5[] = {
{
.name = "gsbi_qup_i2c_addr",
@@ -542,6 +594,10 @@
.id = 0x4009,
};
+struct platform_device mpq_cpudai_pseudo = {
+ .name = "msm-dai-q6",
+ .id = 0x8001,
+};
#define MSM_TSIF0_PHYS (0x18200000)
#define MSM_TSIF1_PHYS (0x18201000)
#define MSM_TSIF_SIZE (0x200)
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index 30a99cd..322347b 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -1083,6 +1083,7 @@
#endif
.disable_dmx = 1,
.disable_fullhd = 0,
+ .cont_mode_dpb_count = 18,
.fw_addr = 0x9fe00000,
};
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 0f71bc4..f8132b4 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -2553,6 +2553,17 @@
};
unsigned msm8960_num_footswitch __initdata = ARRAY_SIZE(msm8960_footswitch);
+struct platform_device *msm8960ab_footswitch[] __initdata = {
+ FS_8X60(FS_MDP, "vdd", "mdp.0", &mdp_fs_data),
+ FS_8X60(FS_ROT, "vdd", "msm_rotator.0", &rot_fs_data),
+ FS_8X60(FS_IJPEG, "vdd", "msm_gemini.0", &ijpeg_fs_data),
+ FS_8X60(FS_VFE, "vdd", "msm_vfe.0", &vfe_fs_data),
+ FS_8X60(FS_VPE, "vdd", "msm_vpe.0", &vpe_fs_data),
+ FS_8X60(FS_GFX3D, "vdd", "kgsl-3d0.0", &gfx3d_fs_data),
+ FS_8X60(FS_VED, "vdd", "msm_vidc.0", &ved_fs_data),
+};
+unsigned msm8960ab_num_footswitch __initdata = ARRAY_SIZE(msm8960ab_footswitch);
+
#ifdef CONFIG_MSM_ROTATOR
static struct msm_bus_vectors rotator_init_vectors[] = {
{
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 8f02050..97adb35 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -216,6 +216,7 @@
extern struct platform_device msm_cpudai0;
extern struct platform_device msm_cpudai1;
extern struct platform_device mpq_cpudai_sec_i2s_rx;
+extern struct platform_device mpq_cpudai_pseudo;
extern struct platform_device msm8960_cpudai_slimbus_2_rx;
extern struct platform_device msm8960_cpudai_slimbus_2_tx;
extern struct platform_device msm_cpudai_hdmi_rx;
@@ -300,6 +301,8 @@
extern unsigned msm8660_num_footswitch;
extern struct platform_device *msm8960_footswitch[];
extern unsigned msm8960_num_footswitch;
+extern struct platform_device *msm8960ab_footswitch[];
+extern unsigned msm8960ab_num_footswitch;
extern struct platform_device *apq8064_footswitch[];
extern unsigned apq8064_num_footswitch;
extern struct platform_device *msm8930_footswitch[];
@@ -413,6 +416,7 @@
extern struct platform_device msm_device_vfe;
extern struct platform_device msm_device_vpe;
extern struct platform_device mpq8064_device_qup_i2c_gsbi5;
+extern struct platform_device mpq8064_device_qup_spi_gsbi6;
extern struct platform_device msm8660_iommu_domain_device;
extern struct platform_device msm8960_iommu_domain_device;
diff --git a/arch/arm/mach-msm/include/mach/clk-provider.h b/arch/arm/mach-msm/include/mach/clk-provider.h
index 770713d..d47e88e 100644
--- a/arch/arm/mach-msm/include/mach/clk-provider.h
+++ b/arch/arm/mach-msm/include/mach/clk-provider.h
@@ -39,8 +39,6 @@
#define ENABLE_VOTED 4 /* Bit pol: 1 = running; delay on disable */
#define DELAY 5 /* No bit to check, just delay */
-#define MAX_VDD_LEVELS 4
-
/**
* struct clk_vdd_class - Voltage scaling class
* @class_name: name of the class
@@ -52,16 +50,19 @@
struct clk_vdd_class {
const char *class_name;
int (*set_vdd)(struct clk_vdd_class *v_class, int level);
- int level_votes[MAX_VDD_LEVELS];
+ int *level_votes;
+ int num_levels;
unsigned long cur_level;
struct mutex lock;
};
-#define DEFINE_VDD_CLASS(_name, _set_vdd) \
+#define DEFINE_VDD_CLASS(_name, _set_vdd, _num_levels) \
struct clk_vdd_class _name = { \
.class_name = #_name, \
.set_vdd = _set_vdd, \
- .cur_level = ARRAY_SIZE(_name.level_votes), \
+ .level_votes = (int [_num_levels]) {}, \
+ .num_levels = _num_levels, \
+ .cur_level = _num_levels, \
.lock = __MUTEX_INITIALIZER(_name.lock) \
}
@@ -109,7 +110,8 @@
const char *dbg_name;
struct clk *depends;
struct clk_vdd_class *vdd_class;
- unsigned long fmax[MAX_VDD_LEVELS];
+ unsigned long *fmax;
+ int num_fmax;
unsigned long rate;
struct list_head children;
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
index 296f222..4c06af4 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -165,4 +165,5 @@
enum apr_subsys_state apr_get_q6_state(void);
int apr_set_q6_state(enum apr_subsys_state state);
void apr_set_subsys_state(void);
+const char *apr_get_lpass_subsys_name(void);
#endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator.h b/arch/arm/mach-msm/include/mach/rpm-regulator.h
index 075d20f..b063b97 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator.h
@@ -101,8 +101,7 @@
* @init_data: regulator constraints
* @id: regulator id; from enum rpm_vreg_id
* @sleep_selectable: flag which indicates that regulator should be accessable
- * by external private API and that spinlocks should be
- * used instead of mutex locks
+ * by external private API
* @system_uA: current drawn from regulator not accounted for by any
* regulator framework consumer
* @enable_time: time in us taken to enable a regulator to the maximum
@@ -184,10 +183,8 @@
* Returns 0 on success or errno.
*
* This function is used to vote for the voltage of a regulator without
- * using the regulator framework. It is needed by consumers which hold spin
- * locks or have interrupts disabled because the regulator framework can sleep.
- * It is also needed by consumers which wish to only vote for active set
- * regulator voltage.
+ * using the regulator framework. It is needed for consumers which wish to only
+ * vote for active set regulator voltage.
*
* If sleep_also == 0, then a sleep-set value of 0V will be voted for.
*
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 20e56c2..3a632e5 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -96,6 +96,13 @@
static struct list_head local_ports[LP_HASH_SIZE];
static DEFINE_MUTEX(local_ports_lock);
+/*
+ * Server info is organized as a hash table. The server's service ID is
+ * used to index into the hash table. The instance ID of most of the servers
+ * are 1 or 2. The service IDs are well distributed compared to the instance
+ * IDs and hence choosing service ID to index into this hash table optimizes
+ * the hash table operations like add, lookup, destroy.
+ */
#define SRV_HASH_SIZE 32
static struct list_head server_list[SRV_HASH_SIZE];
static DEFINE_MUTEX(server_list_lock);
@@ -581,6 +588,20 @@
return;
}
+/**
+ * msm_ipc_router_lookup_server() - Lookup server information
+ * @service: Service ID of the server info to be looked up.
+ * @instance: Instance ID of the server info to be looked up.
+ * @node_id: Node/Processor ID in which the server is hosted.
+ * @port_id: Port ID within the node in which the server is hosted.
+ *
+ * @return: If found Pointer to server structure, else NULL.
+ *
+ * Note1: Lock the server_list_lock before accessing this function.
+ * Note2: If the <node_id:port_id> are <0:0>, then the lookup is restricted
+ * to <service:instance>. Used only when a client wants to send a
+ * message to any QMI server.
+ */
static struct msm_ipc_server *msm_ipc_router_lookup_server(
uint32_t service,
uint32_t instance,
@@ -589,30 +610,39 @@
{
struct msm_ipc_server *server;
struct msm_ipc_server_port *server_port;
- int key = (instance & (SRV_HASH_SIZE - 1));
+ int key = (service & (SRV_HASH_SIZE - 1));
- mutex_lock(&server_list_lock);
list_for_each_entry(server, &server_list[key], list) {
if ((server->name.service != service) ||
(server->name.instance != instance))
continue;
- if ((node_id == 0) && (port_id == 0)) {
- mutex_unlock(&server_list_lock);
+ if ((node_id == 0) && (port_id == 0))
return server;
- }
list_for_each_entry(server_port, &server->server_port_list,
list) {
if ((server_port->server_addr.node_id == node_id) &&
- (server_port->server_addr.port_id == port_id)) {
- mutex_unlock(&server_list_lock);
+ (server_port->server_addr.port_id == port_id))
return server;
- }
}
}
- mutex_unlock(&server_list_lock);
return NULL;
}
+/**
+ * msm_ipc_router_create_server() - Add server info to hash table
+ * @service: Service ID of the server info to be created.
+ * @instance: Instance ID of the server info to be created.
+ * @node_id: Node/Processor ID in which the server is hosted.
+ * @port_id: Port ID within the node in which the server is hosted.
+ * @xprt_info: XPRT through which the node hosting the server is reached.
+ *
+ * @return: Pointer to server structure on success, else NULL.
+ *
+ * This function adds the server info to the hash table. If the same
+ * server(i.e. <service_id:instance_id>) is hosted in different nodes,
+ * they are maintained as list of "server_port" under "server" structure.
+ * Note: Lock the server_list_lock before accessing this function.
+ */
static struct msm_ipc_server *msm_ipc_router_create_server(
uint32_t service,
uint32_t instance,
@@ -622,9 +652,8 @@
{
struct msm_ipc_server *server = NULL;
struct msm_ipc_server_port *server_port;
- int key = (instance & (SRV_HASH_SIZE - 1));
+ int key = (service & (SRV_HASH_SIZE - 1));
- mutex_lock(&server_list_lock);
list_for_each_entry(server, &server_list[key], list) {
if ((server->name.service == service) &&
(server->name.instance == instance))
@@ -633,7 +662,6 @@
server = kmalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
if (!server) {
- mutex_unlock(&server_list_lock);
pr_err("%s: Server allocation failed\n", __func__);
return NULL;
}
@@ -649,7 +677,6 @@
list_del(&server->list);
kfree(server);
}
- mutex_unlock(&server_list_lock);
pr_err("%s: Server Port allocation failed\n", __func__);
return NULL;
}
@@ -657,11 +684,22 @@
server_port->server_addr.port_id = port_id;
server_port->xprt_info = xprt_info;
list_add_tail(&server_port->list, &server->server_port_list);
- mutex_unlock(&server_list_lock);
return server;
}
+/**
+ * msm_ipc_router_destroy_server() - Remove server info from hash table
+ * @server: Server info to be removed.
+ * @node_id: Node/Processor ID in which the server is hosted.
+ * @port_id: Port ID within the node in which the server is hosted.
+ *
+ * This function removes the server_port identified using <node_id:port_id>
+ * from the server structure. If the server_port list under server structure
+ * is empty after removal, then remove the server structure from the server
+ * hash table.
+ * Note: Lock the server_list_lock before accessing this function.
+ */
static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
uint32_t node_id, uint32_t port_id)
{
@@ -670,7 +708,6 @@
if (!server)
return;
- mutex_lock(&server_list_lock);
list_for_each_entry(server_port, &server->server_port_list, list) {
if ((server_port->server_addr.node_id == node_id) &&
(server_port->server_addr.port_id == port_id))
@@ -684,7 +721,6 @@
list_del(&server->list);
kfree(server);
}
- mutex_unlock(&server_list_lock);
return;
}
@@ -1319,6 +1355,7 @@
}
mutex_unlock(&routing_table_lock);
+ mutex_lock(&server_list_lock);
server = msm_ipc_router_lookup_server(msg->srv.service,
msg->srv.instance,
msg->srv.node_id,
@@ -1328,6 +1365,7 @@
msg->srv.service, msg->srv.instance,
msg->srv.node_id, msg->srv.port_id, xprt_info);
if (!server) {
+ mutex_unlock(&server_list_lock);
pr_err("%s: Server Create failed\n", __func__);
return -ENOMEM;
}
@@ -1342,6 +1380,7 @@
}
wake_up(&newserver_wait);
}
+ mutex_unlock(&server_list_lock);
relay_msg(xprt_info, pkt);
post_control_ports(pkt);
@@ -1349,6 +1388,7 @@
case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
RR("o REMOVE_SERVER service=%08x:%d\n",
msg->srv.service, msg->srv.instance);
+ mutex_lock(&server_list_lock);
server = msm_ipc_router_lookup_server(msg->srv.service,
msg->srv.instance,
msg->srv.node_id,
@@ -1360,6 +1400,7 @@
relay_msg(xprt_info, pkt);
post_control_ports(pkt);
}
+ mutex_unlock(&server_list_lock);
break;
case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
RR("o REMOVE_CLIENT id=%d:%08x\n",
@@ -1544,11 +1585,13 @@
if (name->addrtype != MSM_IPC_ADDR_NAME)
return -EINVAL;
+ mutex_lock(&server_list_lock);
server = msm_ipc_router_lookup_server(name->addr.port_name.service,
name->addr.port_name.instance,
IPC_ROUTER_NID_LOCAL,
port_ptr->this_port.port_id);
if (server) {
+ mutex_unlock(&server_list_lock);
pr_err("%s: Server already present\n", __func__);
return -EINVAL;
}
@@ -1559,6 +1602,7 @@
port_ptr->this_port.port_id,
NULL);
if (!server) {
+ mutex_unlock(&server_list_lock);
pr_err("%s: Server Creation failed\n", __func__);
return -EINVAL;
}
@@ -1568,6 +1612,7 @@
ctl.srv.instance = server->name.instance;
ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
ctl.srv.port_id = port_ptr->this_port.port_id;
+ mutex_unlock(&server_list_lock);
broadcast_ctl_msg(&ctl);
spin_lock_irqsave(&port_ptr->port_lock, flags);
port_ptr->type = SERVER_PORT;
@@ -1598,11 +1643,13 @@
return -EINVAL;
}
+ mutex_lock(&server_list_lock);
server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
port_ptr->port_name.instance,
port_ptr->this_port.node_id,
port_ptr->this_port.port_id);
if (!server) {
+ mutex_unlock(&server_list_lock);
pr_err("%s: Server lookup failed\n", __func__);
return -ENODEV;
}
@@ -1612,9 +1659,10 @@
ctl.srv.instance = server->name.instance;
ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
ctl.srv.port_id = port_ptr->this_port.port_id;
- broadcast_ctl_msg(&ctl);
msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
port_ptr->this_port.port_id);
+ mutex_unlock(&server_list_lock);
+ broadcast_ctl_msg(&ctl);
spin_lock_irqsave(&port_ptr->port_lock, flags);
port_ptr->type = CLIENT_PORT;
spin_unlock_irqrestore(&port_ptr->port_lock, flags);
@@ -1813,15 +1861,16 @@
dst_node_id = dest->addr.port_addr.node_id;
dst_port_id = dest->addr.port_addr.port_id;
} else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
+ mutex_lock(&server_list_lock);
server = msm_ipc_router_lookup_server(
dest->addr.port_name.service,
dest->addr.port_name.instance,
0, 0);
if (!server) {
+ mutex_unlock(&server_list_lock);
pr_err("%s: Destination not reachable\n", __func__);
return -ENODEV;
}
- mutex_lock(&server_list_lock);
server_port = list_first_entry(&server->server_port_list,
struct msm_ipc_server_port,
list);
@@ -2005,6 +2054,7 @@
mutex_unlock(&port_ptr->port_rx_q_lock);
if (port_ptr->type == SERVER_PORT) {
+ mutex_lock(&server_list_lock);
server = msm_ipc_router_lookup_server(
port_ptr->port_name.service,
port_ptr->port_name.instance,
@@ -2014,6 +2064,7 @@
msm_ipc_router_destroy_server(server,
port_ptr->this_port.node_id,
port_ptr->this_port.port_id);
+ mutex_unlock(&server_list_lock);
}
wake_lock_destroy(&port_ptr->port_rx_wake_lock);
@@ -2078,27 +2129,24 @@
mutex_lock(&server_list_lock);
if (!lookup_mask)
lookup_mask = 0xFFFFFFFF;
- for (key = 0; key < SRV_HASH_SIZE; key++) {
- list_for_each_entry(server, &server_list[key], list) {
- if ((server->name.service != srv_name->service) ||
- ((server->name.instance & lookup_mask) !=
- srv_name->instance))
- continue;
+ key = (srv_name->service & (SRV_HASH_SIZE - 1));
+ list_for_each_entry(server, &server_list[key], list) {
+ if ((server->name.service != srv_name->service) ||
+ ((server->name.instance & lookup_mask) !=
+ srv_name->instance))
+ continue;
- list_for_each_entry(server_port,
- &server->server_port_list, list) {
- if (i < num_entries_in_array) {
- srv_info[i].node_id =
+ list_for_each_entry(server_port,
+ &server->server_port_list, list) {
+ if (i < num_entries_in_array) {
+ srv_info[i].node_id =
server_port->server_addr.node_id;
- srv_info[i].port_id =
+ srv_info[i].port_id =
server_port->server_addr.port_id;
- srv_info[i].service =
- server->name.service;
- srv_info[i].instance =
- server->name.instance;
- }
- i++;
+ srv_info[i].service = server->name.service;
+ srv_info[i].instance = server->name.instance;
}
+ i++;
}
}
mutex_unlock(&server_list_lock);
diff --git a/arch/arm/mach-msm/msm_mem_hole.c b/arch/arm/mach-msm/msm_mem_hole.c
new file mode 100644
index 0000000..736219b
--- /dev/null
+++ b/arch/arm/mach-msm/msm_mem_hole.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/**
+ * This module exists for the express purpose of removing memory
+ * via the msm memory-remove mechanism (see
+ * Documentation/devicetree/bindings/arm/msm/memory-reserve.txt). Compiling
+ * this module into a kernel is essentially the means by which any
+ * nodes in the device tree with compatible =
+ * "qcom,msm-mem-hole" will be "activated", thus providing a
+ * convenient mechanism for enabling/disabling memory removal
+ * (qcom,memory-*).
+ */
+
+#include <linux/module.h>
+
+#define MSM_MEM_HOLE_COMPAT_STR "qcom,msm-mem-hole"
+
+EXPORT_COMPAT(MSM_MEM_HOLE_COMPAT_STR);
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index 38813e1..37dec30 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -119,7 +119,7 @@
int hw_interconnect;
} ocmem_client_table[OCMEM_CLIENT_MAX] = {
{OCMEM_GRAPHICS, PRIO_GFX, OCMEM_PERFORMANCE, OCMEM_PORT},
- {OCMEM_VIDEO, PRIO_VIDEO, OCMEM_PERFORMANCE, OCMEM_PORT},
+ {OCMEM_VIDEO, PRIO_VIDEO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
{OCMEM_CAMERA, NO_PRIO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
{OCMEM_HP_AUDIO, PRIO_HP_AUDIO, OCMEM_PASSIVE, OCMEM_BLOCKED},
{OCMEM_VOICE, PRIO_VOICE, OCMEM_PASSIVE, OCMEM_BLOCKED},
@@ -157,6 +157,16 @@
return 0;
}
+static inline int is_iface_access(int id)
+{
+ return ocmem_client_table[id].hw_interconnect == OCMEM_OCMEMNOC ? 1 : 0;
+}
+
+static inline int is_remapped_access(int id)
+{
+ return ocmem_client_table[id].hw_interconnect == OCMEM_SYSNOC ? 1 : 0;
+}
+
static inline int is_blocked(int id)
{
return ocmem_client_table[id].hw_interconnect == OCMEM_BLOCKED ? 1 : 0;
@@ -223,9 +233,9 @@
switch (hw_interconnect) {
case OCMEM_PORT:
+ case OCMEM_OCMEMNOC:
ret_addr = phys_to_offset(addr);
break;
- case OCMEM_OCMEMNOC:
case OCMEM_SYSNOC:
ret_addr = addr;
break;
@@ -244,9 +254,9 @@
switch (hw_interconnect) {
case OCMEM_PORT:
+ case OCMEM_OCMEMNOC:
ret_addr = offset_to_phys(addr);
break;
- case OCMEM_OCMEMNOC:
case OCMEM_SYSNOC:
ret_addr = addr;
break;
@@ -588,16 +598,20 @@
if (rc < 0)
goto core_clock_fail;
- rc = ocmem_enable_iface_clock();
- if (rc < 0)
- goto iface_clock_fail;
+ if (is_iface_access(req->owner)) {
+ rc = ocmem_enable_iface_clock();
- rc = ocmem_enable_br_clock();
+ if (rc < 0)
+ goto iface_clock_fail;
+ }
- if (rc < 0)
- goto br_clock_fail;
+ if (is_remapped_access(req->owner)) {
+ rc = ocmem_enable_br_clock();
+ if (rc < 0)
+ goto br_clock_fail;
+ }
rc = ocmem_lock(req->owner, phys_to_offset(req->req_start), req->req_sz,
get_mode(req->owner));
@@ -622,9 +636,11 @@
process_map_fail:
ocmem_unlock(req->owner, phys_to_offset(req->req_start), req->req_sz);
lock_failed:
- ocmem_disable_br_clock();
+ if (is_remapped_access(req->owner))
+ ocmem_disable_br_clock();
br_clock_fail:
- ocmem_disable_iface_clock();
+ if (is_iface_access(req->owner))
+ ocmem_disable_iface_clock();
iface_clock_fail:
ocmem_disable_core_clock();
core_clock_fail:
@@ -651,8 +667,10 @@
goto unlock_failed;
}
- ocmem_disable_br_clock();
- ocmem_disable_iface_clock();
+ if (is_remapped_access(req->owner))
+ ocmem_disable_br_clock();
+ if (is_iface_access(req->owner))
+ ocmem_disable_iface_clock();
ocmem_disable_core_clock();
pr_debug("ocmem: Unmapped request %p\n", req);
return 0;
@@ -1153,6 +1171,37 @@
return 0;
}
+static void sched_dequeue(struct ocmem_req *victim_req)
+{
+ struct ocmem_req *req = NULL;
+ struct ocmem_req *next = NULL;
+ int id;
+
+ if (!victim_req)
+ return;
+
+ id = victim_req->owner;
+
+ mutex_lock(&sched_queue_mutex);
+
+ if (list_empty(&sched_queue[id]))
+ goto dequeue_done;
+
+ list_for_each_entry_safe(req, next, &sched_queue[id], sched_list)
+ {
+ if (req == victim_req) {
+ pr_debug("ocmem: Cancelling pending request %p\n",
+ req);
+ list_del(&req->sched_list);
+ goto dequeue_done;
+ }
+ }
+
+dequeue_done:
+ mutex_unlock(&sched_queue_mutex);
+ return;
+}
+
static struct ocmem_req *ocmem_fetch_req(void)
{
int i;
@@ -1379,6 +1428,10 @@
return -EINVAL;
}
+ mutex_lock(&sched_mutex);
+ sched_dequeue(req);
+ mutex_unlock(&sched_mutex);
+
if (!TEST_STATE(req, R_FREE)) {
rc = process_unmap(req, req->req_start, req->req_end);
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index f3c731f..b856d05 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -38,9 +38,6 @@
#define MSS_MODEM_HALT_BASE 0x200
#define MSS_NC_HALT_BASE 0x280
-/* MSS_CLAMP_IO Register Value */
-#define MSS_IO_UNCLAMP_ALL 0x40
-
/* RMB Status Register Values */
#define STATUS_PBL_SUCCESS 0x1
#define STATUS_XPU_UNLOCKED 0x1
@@ -200,9 +197,6 @@
drv->reg_base + QDSP6SS_RST_EVB);
}
- /* De-assert MSS IO clamps */
- writel_relaxed(MSS_IO_UNCLAMP_ALL, drv->io_clamp_reg);
-
ret = pil_q6v5_reset(pil);
if (ret)
goto err_q6v5_reset;
@@ -270,12 +264,6 @@
if (!drv->restart_reg)
return -ENOMEM;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clamp_reg");
- drv->io_clamp_reg = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- if (!drv->io_clamp_reg)
- return -ENOMEM;
-
drv->vreg = devm_regulator_get(&pdev->dev, "vdd_mss");
if (IS_ERR(drv->vreg))
return PTR_ERR(drv->vreg);
diff --git a/arch/arm/mach-msm/pil-q6v5.h b/arch/arm/mach-msm/pil-q6v5.h
index f176d2d..7304757 100644
--- a/arch/arm/mach-msm/pil-q6v5.h
+++ b/arch/arm/mach-msm/pil-q6v5.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -31,7 +31,6 @@
void __iomem *axi_halt_base;
void __iomem *rmb_base;
void __iomem *restart_reg;
- void __iomem *io_clamp_reg;
unsigned long start_addr;
struct regulator *vreg;
bool is_booted;
diff --git a/arch/arm/mach-msm/pil-tzapps.c b/arch/arm/mach-msm/pil-tzapps.c
index 2345453..be78fab 100644
--- a/arch/arm/mach-msm/pil-tzapps.c
+++ b/arch/arm/mach-msm/pil-tzapps.c
@@ -16,9 +16,18 @@
#include <linux/elf.h>
#include <linux/err.h>
+#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
+
#include "peripheral-loader.h"
#include "scm-pas.h"
+struct tzapps_data {
+ struct pil_device *pil;
+ struct subsys_device *subsys;
+ struct subsys_desc subsys_desc;
+};
+
static int pil_tzapps_init_image(struct pil_desc *pil, const u8 *metadata,
size_t size)
{
@@ -41,10 +50,28 @@
.shutdown = pil_tzapps_shutdown,
};
+#define subsys_to_drv(d) container_of(d, struct tzapps_data, subsys_desc)
+
+static int tzapps_start(const struct subsys_desc *desc)
+{
+ void *ret;
+
+ ret = pil_get("tzapps");
+ if (IS_ERR(ret))
+ return PTR_ERR(ret);
+ return 0;
+}
+
+static void tzapps_stop(const struct subsys_desc *desc)
+{
+ struct tzapps_data *drv = subsys_to_drv(desc);
+ pil_put(drv->pil);
+}
+
static int __devinit pil_tzapps_driver_probe(struct platform_device *pdev)
{
struct pil_desc *desc;
- struct pil_device *pil;
+ struct tzapps_data *drv;
if (pas_supported(PAS_TZAPPS) < 0)
return -ENOSYS;
@@ -53,21 +80,38 @@
if (!desc)
return -ENOMEM;
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, drv);
+
desc->name = "tzapps";
desc->dev = &pdev->dev;
desc->ops = &pil_tzapps_ops;
desc->owner = THIS_MODULE;
- pil = msm_pil_register(desc);
- if (IS_ERR(pil))
- return PTR_ERR(pil);
- platform_set_drvdata(pdev, pil);
+ drv->pil = msm_pil_register(desc);
+ if (IS_ERR(drv->pil))
+ return PTR_ERR(drv->pil);
+
+ drv->subsys_desc.name = "tzapps";
+ drv->subsys_desc.dev = &pdev->dev;
+ drv->subsys_desc.owner = THIS_MODULE;
+ drv->subsys_desc.start = tzapps_start;
+ drv->subsys_desc.stop = tzapps_stop;
+
+ drv->subsys = subsys_register(&drv->subsys_desc);
+ if (IS_ERR(drv->subsys)) {
+ msm_pil_unregister(drv->pil);
+ return PTR_ERR(drv->subsys);
+ }
return 0;
}
static int __devexit pil_tzapps_driver_exit(struct platform_device *pdev)
{
- struct pil_device *pil = platform_get_drvdata(pdev);
- msm_pil_unregister(pil);
+ struct tzapps_data *drv = platform_get_drvdata(pdev);
+ subsys_unregister(drv->subsys);
+ msm_pil_unregister(drv->pil);
return 0;
}
diff --git a/arch/arm/mach-msm/pil-venus.c b/arch/arm/mach-msm/pil-venus.c
index e331296..e3125cf 100644
--- a/arch/arm/mach-msm/pil-venus.c
+++ b/arch/arm/mach-msm/pil-venus.c
@@ -28,6 +28,8 @@
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
+#include <mach/subsystem_restart.h>
+#include <mach/peripheral-loader.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
@@ -66,6 +68,8 @@
void __iomem *venus_wrapper_base;
void __iomem *venus_vbif_base;
struct pil_device *pil;
+ struct subsys_device *subsys;
+ struct subsys_desc subsys_desc;
struct regulator *gdsc;
phys_addr_t start_addr;
struct clk *clks[ARRAY_SIZE(clk_names)];
@@ -78,6 +82,8 @@
u32 fw_max_paddr;
};
+#define subsys_to_drv(d) container_of(d, struct venus_data, subsys_desc)
+
static int venus_register_domain(u32 fw_max_sz)
{
struct msm_iova_partition venus_fw_partition = {
@@ -381,6 +387,23 @@
.proxy_unvote = pil_venus_remove_proxy_vote,
};
+static int venus_start(const struct subsys_desc *desc)
+{
+ void *ret;
+ struct venus_data *drv = subsys_to_drv(desc);
+
+ ret = pil_get(drv->subsys_desc.name);
+ if (IS_ERR(ret))
+ return PTR_ERR(ret);
+ return 0;
+}
+
+static void venus_stop(const struct subsys_desc *desc)
+{
+ struct venus_data *drv = subsys_to_drv(desc);
+ pil_put(drv->pil);
+}
+
static int __devinit pil_venus_probe(struct platform_device *pdev)
{
struct venus_data *drv;
@@ -488,12 +511,25 @@
if (IS_ERR(drv->pil))
return PTR_ERR(drv->pil);
+ drv->subsys_desc.name = desc->name;
+ drv->subsys_desc.owner = THIS_MODULE;
+ drv->subsys_desc.dev = &pdev->dev;
+ drv->subsys_desc.start = venus_start;
+ drv->subsys_desc.stop = venus_stop;
+
+ drv->subsys = subsys_register(&drv->subsys_desc);
+ if (IS_ERR(drv->subsys)) {
+ msm_pil_unregister(drv->pil);
+ return PTR_ERR(drv->subsys);
+ }
+
return 0;
}
static int __devexit pil_venus_remove(struct platform_device *pdev)
{
struct venus_data *drv = platform_get_drvdata(pdev);
+ subsys_unregister(drv->subsys);
msm_pil_unregister(drv->pil);
return 0;
diff --git a/arch/arm/mach-msm/pil-vidc.c b/arch/arm/mach-msm/pil-vidc.c
index e4c6a2d..b2609b1 100644
--- a/arch/arm/mach-msm/pil-vidc.c
+++ b/arch/arm/mach-msm/pil-vidc.c
@@ -17,6 +17,9 @@
#include <linux/err.h>
#include <linux/clk.h>
+#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
+
#include "peripheral-loader.h"
#include "scm-pas.h"
@@ -24,6 +27,8 @@
struct clk *smmu_iface;
struct clk *core;
struct pil_device *pil;
+ struct subsys_device *subsys;
+ struct subsys_desc subsys_desc;
};
static int pil_vidc_init_image(struct pil_desc *pil, const u8 *metadata,
@@ -63,6 +68,24 @@
.shutdown = pil_vidc_shutdown,
};
+#define subsys_to_drv(d) container_of(d, struct vidc_data, subsys_desc)
+
+static int vidc_start(const struct subsys_desc *desc)
+{
+ void *ret;
+
+ ret = pil_get("vidc");
+ if (IS_ERR(ret))
+ return PTR_ERR(ret);
+ return 0;
+}
+
+static void vidc_stop(const struct subsys_desc *desc)
+{
+ struct vidc_data *drv = subsys_to_drv(desc);
+ pil_put(drv->pil);
+}
+
static int __devinit pil_vidc_driver_probe(struct platform_device *pdev)
{
struct pil_desc *desc;
@@ -95,12 +118,25 @@
drv->pil = msm_pil_register(desc);
if (IS_ERR(drv->pil))
return PTR_ERR(drv->pil);
+
+ drv->subsys_desc.name = "vidc";
+ drv->subsys_desc.dev = &pdev->dev;
+ drv->subsys_desc.owner = THIS_MODULE;
+ drv->subsys_desc.start = vidc_start;
+ drv->subsys_desc.stop = vidc_stop;
+
+ drv->subsys = subsys_register(&drv->subsys_desc);
+ if (IS_ERR(drv->subsys)) {
+ msm_pil_unregister(drv->pil);
+ return PTR_ERR(drv->subsys);
+ }
return 0;
}
static int __devexit pil_vidc_driver_exit(struct platform_device *pdev)
{
struct vidc_data *drv = platform_get_drvdata(pdev);
+ subsys_unregister(drv->subsys);
msm_pil_unregister(drv->pil);
return 0;
}
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 5f05f98..0933d20 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -103,8 +103,7 @@
if (!base_ptr)
return -ENODEV;
- if (machine_is_msm8974_sim() || machine_is_mpq8092_sim() ||
- machine_is_msm8226_sim()) {
+ if (machine_is_msm8974_sim() || machine_is_mpq8092_sim()) {
writel_relaxed(0x800, base_ptr+0x04);
writel_relaxed(0x3FFF, base_ptr+0x14);
}
@@ -179,8 +178,7 @@
if (cpu_is_msm8x60())
return scorpion_release_secondary();
- if (machine_is_msm8974_sim() || machine_is_mpq8092_sim() ||
- machine_is_msm8226_sim())
+ if (machine_is_msm8974_sim() || machine_is_mpq8092_sim())
return krait_release_secondary_sim(0xf9088000, cpu);
if (soc_class_is_msm8960() || soc_class_is_msm8930() ||
diff --git a/arch/arm/mach-msm/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
index 3731722..0f17a0b 100644
--- a/arch/arm/mach-msm/qdsp6v2/Makefile
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -8,6 +8,7 @@
obj-y += q6voice.o
obj-y += snddev_hdmi.o
obj-y += audio_mvs.o
+obj-$(CONFIG_ARCH_MSM8X60) += pcm_in_proxy.o
obj-$(CONFIG_FB_MSM_HDMI_MSM_PANEL) += lpa_if_hdmi.o
endif
obj-$(CONFIG_MSM_QDSP6_APR) += apr.o apr_v1.o apr_tal.o q6core.o dsp_debug.o
diff --git a/arch/arm/mach-msm/qdsp6v2/adsprpc.c b/arch/arm/mach-msm/qdsp6v2/adsprpc.c
index 49008de..822da91 100644
--- a/arch/arm/mach-msm/qdsp6v2/adsprpc.c
+++ b/arch/arm/mach-msm/qdsp6v2/adsprpc.c
@@ -11,6 +11,7 @@
* GNU General Public License for more details.
*
*/
+#include <linux/scatterlist.h>
#include "adsprpc.h"
struct smq_invoke_ctx {
@@ -70,14 +71,25 @@
static int alloc_mem(struct fastrpc_buf *buf)
{
struct ion_client *clnt = gfa.iclient;
+ struct sg_table *sg;
int err = 0;
buf->handle = ion_alloc(clnt, buf->size, SZ_4K,
ION_HEAP(ION_AUDIO_HEAP_ID), 0);
- VERIFY(0 == IS_ERR_OR_NULL(buf->handle));
+ VERIFY(err, 0 == IS_ERR_OR_NULL(buf->handle));
+ if (err)
+ goto bail;
buf->virt = 0;
- VERIFY(0 != (buf->virt = ion_map_kernel(clnt, buf->handle)));
- VERIFY(0 == ion_phys(clnt, buf->handle, &buf->phys, &buf->size));
+ VERIFY(err, 0 != (buf->virt = ion_map_kernel(clnt, buf->handle)));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 != (sg = ion_sg_table(clnt, buf->handle)));
+ if (err)
+ goto bail;
+ VERIFY(err, 1 == sg->nents);
+ if (err)
+ goto bail;
+ buf->phys = sg_dma_address(sg->sgl);
bail:
if (err && !IS_ERR_OR_NULL(buf->handle))
free_mem(buf);
@@ -87,7 +99,9 @@
static int context_list_ctor(struct smq_context_list *me, int size)
{
int err = 0;
- VERIFY(0 != (me->ls = kzalloc(size, GFP_KERNEL)));
+ VERIFY(err, 0 != (me->ls = kzalloc(size, GFP_KERNEL)));
+ if (err)
+ goto bail;
me->size = size / sizeof(*me->ls);
me->last = 0;
bail:
@@ -103,18 +117,18 @@
static void context_list_alloc_ctx(struct smq_context_list *me,
struct smq_invoke_ctx **po)
{
- int ii = me->last;
+ int i = me->last;
struct smq_invoke_ctx *ctx;
for (;;) {
- ii = ii % me->size;
- ctx = &me->ls[ii];
+ i = i % me->size;
+ ctx = &me->ls[i];
if (atomic_read(&ctx->free) == 0)
- if (0 == atomic_cmpxchg(&ctx->free, 0, 1))
+ if (atomic_cmpxchg(&ctx->free, 0, 1) == 0)
break;
- ii++;
+ i++;
}
- me->last = ii;
+ me->last = i;
ctx->retval = -1;
init_completion(&ctx->work);
*po = ctx;
@@ -134,13 +148,13 @@
static void context_notify_all_users(struct smq_context_list *me)
{
- int ii;
+ int i;
if (!me->ls)
return;
- for (ii = 0; ii < me->size; ++ii) {
- if (atomic_read(&me->ls[ii].free) != 0)
- complete(&me->ls[ii].work);
+ for (i = 0; i < me->size; ++i) {
+ if (atomic_read(&me->ls[i].free) != 0)
+ complete(&me->ls[i].work);
}
}
@@ -149,11 +163,10 @@
{
struct smq_phy_page *pgstart, *pages;
struct smq_invoke_buf *list;
- int ii, rlen, err = 0;
+ int i, rlen, err = 0;
int inbufs = REMOTE_SCALARS_INBUFS(sc);
int outbufs = REMOTE_SCALARS_OUTBUFS(sc);
- VERIFY(0 != try_module_get(THIS_MODULE));
LOCK_MMAP(kernel);
*obuf = *ibuf;
retry:
@@ -165,38 +178,46 @@
rlen = ((uint32_t)pages - (uint32_t)obuf->virt) - obuf->size;
obuf->size += buf_page_size(rlen);
obuf->handle = 0;
- VERIFY(0 == alloc_mem(obuf));
+ VERIFY(err, 0 == alloc_mem(obuf));
+ if (err)
+ goto bail;
goto retry;
}
pgstart->addr = obuf->phys;
pgstart->size = obuf->size;
- for (ii = 0; ii < inbufs + outbufs; ++ii) {
+ for (i = 0; i < inbufs + outbufs; ++i) {
void *buf;
int len, num;
- len = pra[ii].buf.len;
+ list[i].num = 0;
+ list[i].pgidx = 0;
+ len = pra[i].buf.len;
if (!len)
continue;
- buf = pra[ii].buf.pv;
+ buf = pra[i].buf.pv;
num = buf_num_pages(buf, len);
if (!kernel)
- list[ii].num = buf_get_pages(buf, len, num,
- ii >= inbufs, pages, rlen / sizeof(*pages));
+ list[i].num = buf_get_pages(buf, len, num,
+ i >= inbufs, pages, rlen / sizeof(*pages));
else
- list[ii].num = 0;
- VERIFY(list[ii].num >= 0);
- if (list[ii].num) {
- list[ii].pgidx = pages - pgstart;
- pages = pages + list[ii].num;
+ list[i].num = 0;
+ VERIFY(err, list[i].num >= 0);
+ if (err)
+ goto bail;
+ if (list[i].num) {
+ list[i].pgidx = pages - pgstart;
+ pages = pages + list[i].num;
} else if (rlen > sizeof(*pages)) {
- list[ii].pgidx = pages - pgstart;
+ list[i].pgidx = pages - pgstart;
pages = pages + 1;
} else {
if (obuf->handle != ibuf->handle)
free_mem(obuf);
obuf->size += buf_page_size(sizeof(*pages));
obuf->handle = 0;
- VERIFY(0 == alloc_mem(obuf));
+ VERIFY(err, 0 == alloc_mem(obuf));
+ if (err)
+ goto bail;
goto retry;
}
rlen = obuf->size - ((uint32_t) pages - (uint32_t) obuf->virt);
@@ -206,7 +227,6 @@
if (err && (obuf->handle != ibuf->handle))
free_mem(obuf);
UNLOCK_MMAP(kernel);
- module_put(THIS_MODULE);
return err;
}
@@ -219,74 +239,86 @@
struct fastrpc_buf *pbuf = ibuf, *obufs = 0;
struct smq_phy_page *pages;
void *args;
- int ii, rlen, size, used, inh, bufs = 0, err = 0;
+ int i, rlen, size, used, inh, bufs = 0, err = 0;
int inbufs = REMOTE_SCALARS_INBUFS(sc);
int outbufs = REMOTE_SCALARS_OUTBUFS(sc);
list = smq_invoke_buf_start(rpra, sc);
pages = smq_phy_page_start(sc, list);
- used = ALIGN_8(pbuf->used);
+ used = ALIGN(pbuf->used, BALIGN);
args = (void *)((char *)pbuf->virt + used);
rlen = pbuf->size - used;
- for (ii = 0; ii < inbufs + outbufs; ++ii) {
+ for (i = 0; i < inbufs + outbufs; ++i) {
int num;
- rpra[ii].buf.len = pra[ii].buf.len;
- if (list[ii].num) {
- rpra[ii].buf.pv = pra[ii].buf.pv;
+ rpra[i].buf.len = pra[i].buf.len;
+ if (!rpra[i].buf.len)
+ continue;
+ if (list[i].num) {
+ rpra[i].buf.pv = pra[i].buf.pv;
continue;
}
- if (rlen < pra[ii].buf.len) {
+ if (rlen < pra[i].buf.len) {
struct fastrpc_buf *b;
pbuf->used = pbuf->size - rlen;
- VERIFY(0 != (b = krealloc(obufs,
+ VERIFY(err, 0 != (b = krealloc(obufs,
(bufs + 1) * sizeof(*obufs), GFP_KERNEL)));
+ if (err)
+ goto bail;
obufs = b;
pbuf = obufs + bufs;
- pbuf->size = buf_num_pages(0, pra[ii].buf.len) *
+ pbuf->size = buf_num_pages(0, pra[i].buf.len) *
PAGE_SIZE;
- VERIFY(0 == alloc_mem(pbuf));
+ VERIFY(err, 0 == alloc_mem(pbuf));
+ if (err)
+ goto bail;
bufs++;
args = pbuf->virt;
rlen = pbuf->size;
}
- num = buf_num_pages(args, pra[ii].buf.len);
+ num = buf_num_pages(args, pra[i].buf.len);
if (pbuf == ibuf) {
- list[ii].num = num;
- list[ii].pgidx = 0;
+ list[i].num = num;
+ list[i].pgidx = 0;
} else {
- list[ii].num = 1;
- pages[list[ii].pgidx].addr =
+ list[i].num = 1;
+ pages[list[i].pgidx].addr =
buf_page_start((void *)(pbuf->phys +
(pbuf->size - rlen)));
- pages[list[ii].pgidx].size =
- buf_page_size(pra[ii].buf.len);
+ pages[list[i].pgidx].size =
+ buf_page_size(pra[i].buf.len);
}
- if (ii < inbufs) {
- if (!kernel)
- VERIFY(0 == copy_from_user(args, pra[ii].buf.pv,
- pra[ii].buf.len));
- else
- memmove(args, pra[ii].buf.pv, pra[ii].buf.len);
+ if (i < inbufs) {
+ if (!kernel) {
+ VERIFY(err, 0 == copy_from_user(args,
+ pra[i].buf.pv, pra[i].buf.len));
+ if (err)
+ goto bail;
+ } else {
+ memmove(args, pra[i].buf.pv, pra[i].buf.len);
+ }
}
- rpra[ii].buf.pv = args;
- args = (void *)((char *)args + ALIGN_8(pra[ii].buf.len));
- rlen -= ALIGN_8(pra[ii].buf.len);
+ rpra[i].buf.pv = args;
+ args = (void *)((char *)args + ALIGN(pra[i].buf.len, BALIGN));
+ rlen -= ALIGN(pra[i].buf.len, BALIGN);
}
- for (ii = 0; ii < inbufs; ++ii) {
- if (rpra[ii].buf.len)
- dmac_flush_range(rpra[ii].buf.pv,
- (char *)rpra[ii].buf.pv + rpra[ii].buf.len);
+ for (i = 0; i < inbufs; ++i) {
+ if (rpra[i].buf.len)
+ dmac_flush_range(rpra[i].buf.pv,
+ (char *)rpra[i].buf.pv + rpra[i].buf.len);
}
pbuf->used = pbuf->size - rlen;
size = sizeof(*rpra) * REMOTE_SCALARS_INHANDLES(sc);
if (size) {
inh = inbufs + outbufs;
- if (!kernel)
- VERIFY(0 == copy_from_user(&rpra[inh], &upra[inh],
+ if (!kernel) {
+ VERIFY(err, 0 == copy_from_user(&rpra[inh], &upra[inh],
size));
- else
+ if (err)
+ goto bail;
+ } else {
memmove(&rpra[inh], &upra[inh], size);
+ }
}
dmac_flush_range(rpra, (char *)rpra + used);
bail:
@@ -298,24 +330,30 @@
static int put_args(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
remote_arg_t *rpra, remote_arg_t *upra)
{
- int ii, inbufs, outbufs, outh, size;
+ int i, inbufs, outbufs, outh, size;
int err = 0;
inbufs = REMOTE_SCALARS_INBUFS(sc);
outbufs = REMOTE_SCALARS_OUTBUFS(sc);
- for (ii = inbufs; ii < inbufs + outbufs; ++ii) {
- if (rpra[ii].buf.pv != pra[ii].buf.pv)
- VERIFY(0 == copy_to_user(pra[ii].buf.pv,
- rpra[ii].buf.pv, rpra[ii].buf.len));
+ for (i = inbufs; i < inbufs + outbufs; ++i) {
+ if (rpra[i].buf.pv != pra[i].buf.pv) {
+ VERIFY(err, 0 == copy_to_user(pra[i].buf.pv,
+ rpra[i].buf.pv, rpra[i].buf.len));
+ if (err)
+ goto bail;
+ }
}
size = sizeof(*rpra) * REMOTE_SCALARS_OUTHANDLES(sc);
if (size) {
outh = inbufs + outbufs + REMOTE_SCALARS_INHANDLES(sc);
- if (!kernel)
- VERIFY(0 == copy_to_user(&upra[outh], &rpra[outh],
+ if (!kernel) {
+ VERIFY(err, 0 == copy_to_user(&upra[outh], &rpra[outh],
size));
- else
+ if (err)
+ goto bail;
+ } else {
memmove(&upra[outh], &rpra[outh], size);
+ }
}
bail:
return err;
@@ -323,24 +361,24 @@
static void inv_args(uint32_t sc, remote_arg_t *rpra, int used)
{
- int ii, inbufs, outbufs;
+ int i, inbufs, outbufs;
int inv = 0;
inbufs = REMOTE_SCALARS_INBUFS(sc);
outbufs = REMOTE_SCALARS_OUTBUFS(sc);
- for (ii = inbufs; ii < inbufs + outbufs; ++ii) {
- if (buf_page_start(rpra) == buf_page_start(rpra[ii].buf.pv))
+ for (i = inbufs; i < inbufs + outbufs; ++i) {
+ if (buf_page_start(rpra) == buf_page_start(rpra[i].buf.pv))
inv = 1;
- else
- dmac_inv_range(rpra[ii].buf.pv,
- (char *)rpra[ii].buf.pv + rpra[ii].buf.len);
+ else if (rpra[i].buf.len)
+ dmac_inv_range(rpra[i].buf.pv,
+ (char *)rpra[i].buf.pv + rpra[i].buf.len);
}
if (inv || REMOTE_SCALARS_OUTHANDLES(sc))
dmac_inv_range(rpra, (char *)rpra + used);
}
-static int fastrpc_invoke_send(struct fastrpc_apps *me, remote_handle_t handle,
+static int fastrpc_invoke_send(struct fastrpc_apps *me, uint32_t handle,
uint32_t sc, struct smq_invoke_ctx *ctx,
struct fastrpc_buf *buf)
{
@@ -357,8 +395,7 @@
spin_lock(&me->wrlock);
len = smd_write(me->chan, &msg, sizeof(msg));
spin_unlock(&me->wrlock);
- VERIFY(len == sizeof(msg));
- bail:
+ VERIFY(err, len == sizeof(msg));
return err;
}
@@ -369,7 +406,8 @@
if (me->chan)
(void)smd_close(me->chan);
context_list_dtor(&me->clst);
- ion_client_destroy(me->iclient);
+ if (me->iclient)
+ ion_client_destroy(me->iclient);
me->iclient = 0;
me->chan = 0;
}
@@ -381,8 +419,10 @@
int err = 0;
do {
- VERIFY(sizeof(rsp) ==
+ VERIFY(err, sizeof(rsp) ==
smd_read_from_cb(me->chan, &rsp, sizeof(rsp)));
+ if (err)
+ goto bail;
context_notify_user(rsp.ctx, rsp.retval);
} while (!err);
bail:
@@ -412,21 +452,29 @@
struct fastrpc_apps *me = &gfa;
if (me->chan == 0) {
- int ii;
+ int i;
spin_lock_init(&me->hlock);
spin_lock_init(&me->wrlock);
init_completion(&me->work);
- for (ii = 0; ii < RPC_HASH_SZ; ++ii)
- INIT_HLIST_HEAD(&me->htbl[ii]);
- VERIFY(0 == context_list_ctor(&me->clst, SZ_4K));
+ for (i = 0; i < RPC_HASH_SZ; ++i)
+ INIT_HLIST_HEAD(&me->htbl[i]);
+ VERIFY(err, 0 == context_list_ctor(&me->clst, SZ_4K));
+ if (err)
+ goto bail;
me->iclient = msm_ion_client_create(ION_HEAP_CARVEOUT_MASK,
DEVICE_NAME);
- VERIFY(0 == IS_ERR_OR_NULL(me->iclient));
- VERIFY(0 == smd_named_open_on_edge(FASTRPC_SMD_GUID,
+ VERIFY(err, 0 == IS_ERR_OR_NULL(me->iclient));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 == smd_named_open_on_edge(FASTRPC_SMD_GUID,
SMD_APPS_QDSP, &me->chan,
me, smd_event_handler));
- VERIFY(0 != wait_for_completion_timeout(&me->work,
+ if (err)
+ goto bail;
+ VERIFY(err, 0 != wait_for_completion_timeout(&me->work,
RPC_TIMEOUT));
+ if (err)
+ goto bail;
}
bail:
if (err)
@@ -448,10 +496,16 @@
int err = 0;
struct fastrpc_device *fd = 0;
- VERIFY(0 != try_module_get(THIS_MODULE));
- VERIFY(0 != (fd = kzalloc(sizeof(*fd), GFP_KERNEL)));
+ VERIFY(err, 0 != try_module_get(THIS_MODULE));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 != (fd = kzalloc(sizeof(*fd), GFP_KERNEL)));
+ if (err)
+ goto bail;
fd->buf.size = PAGE_SIZE;
- VERIFY(0 == alloc_mem(&fd->buf));
+ VERIFY(err, 0 == alloc_mem(&fd->buf));
+ if (err)
+ goto bail;
fd->tgid = current->tgid;
INIT_HLIST_NODE(&fd->hn);
*dev = fd;
@@ -478,7 +532,9 @@
}
}
spin_unlock(&me->hlock);
- VERIFY(dev != 0);
+ VERIFY(err, dev != 0);
+ if (err)
+ goto bail;
*rdev = dev;
bail:
if (err) {
@@ -511,34 +567,49 @@
struct fastrpc_buf obuf, *abufs = 0, *b;
int interrupted = 0;
uint32_t sc;
- int ii, nbufs = 0, err = 0;
+ int i, nbufs = 0, err = 0;
sc = invoke->sc;
obuf.handle = 0;
if (REMOTE_SCALARS_LENGTH(sc)) {
- VERIFY(0 == get_dev(me, &dev));
- VERIFY(0 == get_page_list(kernel, sc, pra, &dev->buf, &obuf));
+ VERIFY(err, 0 == get_dev(me, &dev));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 == get_page_list(kernel, sc, pra, &dev->buf,
+ &obuf));
+ if (err)
+ goto bail;
rpra = (remote_arg_t *)obuf.virt;
- VERIFY(0 == get_args(kernel, sc, pra, rpra, invoke->pra, &obuf,
- &abufs, &nbufs));
+ VERIFY(err, 0 == get_args(kernel, sc, pra, rpra, invoke->pra,
+ &obuf, &abufs, &nbufs));
+ if (err)
+ goto bail;
}
context_list_alloc_ctx(&me->clst, &ctx);
- VERIFY(0 == fastrpc_invoke_send(me, invoke->handle, sc, ctx, &obuf));
+ VERIFY(err, 0 == fastrpc_invoke_send(me, invoke->handle, sc, ctx,
+ &obuf));
+ if (err)
+ goto bail;
inv_args(sc, rpra, obuf.used);
- VERIFY(0 == (interrupted =
+ VERIFY(err, 0 == (interrupted =
wait_for_completion_interruptible(&ctx->work)));
- VERIFY(0 == (err = ctx->retval));
- VERIFY(0 == put_args(kernel, sc, pra, rpra, invoke->pra));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 == (err = ctx->retval));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 == put_args(kernel, sc, pra, rpra, invoke->pra));
+ if (err)
+ goto bail;
bail:
if (interrupted) {
- init_completion(&ctx->work);
if (!kernel)
(void)fastrpc_release_current_dsp_process();
wait_for_completion(&ctx->work);
}
context_free(ctx);
- for (ii = 0, b = abufs; ii < nbufs; ++ii, ++b)
+ for (i = 0, b = abufs; i < nbufs; ++i, ++b)
free_mem(b);
kfree(abufs);
if (dev) {
@@ -563,8 +634,7 @@
ioctl.handle = 1;
ioctl.sc = REMOTE_SCALARS_MAKE(0, 1, 0);
ioctl.pra = ra;
- VERIFY(0 == fastrpc_internal_invoke(me, 1, &ioctl, ra));
- bail:
+ VERIFY(err, 0 == fastrpc_internal_invoke(me, 1, &ioctl, ra));
return err;
}
@@ -582,8 +652,7 @@
ioctl.handle = 1;
ioctl.sc = REMOTE_SCALARS_MAKE(1, 1, 0);
ioctl.pra = ra;
- VERIFY(0 == fastrpc_internal_invoke(me, 1, &ioctl, ra));
- bail:
+ VERIFY(err, 0 == fastrpc_internal_invoke(me, 1, &ioctl, ra));
return err;
}
@@ -628,8 +697,7 @@
/* This call will cause a dev to be created
* which will addref this module
*/
- VERIFY(0 == fastrpc_create_current_dsp_process());
- bail:
+ VERIFY(err, 0 == fastrpc_create_current_dsp_process());
if (err)
cleanup_current_dev();
module_put(THIS_MODULE);
@@ -649,19 +717,28 @@
switch (ioctl_num) {
case FASTRPC_IOCTL_INVOKE:
- VERIFY(0 == copy_from_user(&invoke, param, sizeof(invoke)));
+ VERIFY(err, 0 == copy_from_user(&invoke, param,
+ sizeof(invoke)));
+ if (err)
+ goto bail;
bufs = REMOTE_SCALARS_INBUFS(invoke.sc) +
REMOTE_SCALARS_OUTBUFS(invoke.sc);
if (bufs) {
bufs = bufs * sizeof(*pra);
- VERIFY(0 != (pra = kmalloc(bufs, GFP_KERNEL)));
+ VERIFY(err, 0 != (pra = kmalloc(bufs, GFP_KERNEL)));
+ if (err)
+ goto bail;
}
- VERIFY(0 == copy_from_user(pra, invoke.pra, bufs));
- VERIFY(0 == (err = fastrpc_internal_invoke(me, 0, &invoke,
+ VERIFY(err, 0 == copy_from_user(pra, invoke.pra, bufs));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 0, &invoke,
pra)));
+ if (err)
+ goto bail;
break;
default:
- err = -EINVAL;
+ err = -ENOTTY;
break;
}
bail:
@@ -680,13 +757,24 @@
struct fastrpc_apps *me = &gfa;
int err = 0;
- VERIFY(0 == fastrpc_init());
- VERIFY(0 == alloc_chrdev_region(&me->dev_no, 0, 1, DEVICE_NAME));
+ VERIFY(err, 0 == fastrpc_init());
+ if (err)
+ goto bail;
+ VERIFY(err, 0 == alloc_chrdev_region(&me->dev_no, 0, 1, DEVICE_NAME));
+ if (err)
+ goto bail;
cdev_init(&me->cdev, &fops);
me->cdev.owner = THIS_MODULE;
- VERIFY(0 == cdev_add(&me->cdev, MKDEV(MAJOR(me->dev_no), 0), 1));
+ VERIFY(err, 0 == cdev_add(&me->cdev, MKDEV(MAJOR(me->dev_no), 0), 1));
+ if (err)
+ goto bail;
pr_info("'mknod /dev/%s c %d 0'\n", DEVICE_NAME, MAJOR(me->dev_no));
bail:
+ if (err) {
+ if (me->dev_no)
+ unregister_chrdev_region(me->dev_no, 1);
+ fastrpc_deinit();
+ }
return err;
}
diff --git a/arch/arm/mach-msm/qdsp6v2/adsprpc.h b/arch/arm/mach-msm/qdsp6v2/adsprpc.h
index c6c7d23..3f1b4a7 100644
--- a/arch/arm/mach-msm/qdsp6v2/adsprpc.h
+++ b/arch/arm/mach-msm/qdsp6v2/adsprpc.h
@@ -36,8 +36,7 @@
#define RPC_TIMEOUT (5 * HZ)
#define RPC_HASH_BITS 5
#define RPC_HASH_SZ (1 << RPC_HASH_BITS)
-
-#define ALIGN_8(a) ALIGN(a, 8)
+#define BALIGN 32
#define LOCK_MMAP(kernel)\
do {\
@@ -84,18 +83,26 @@
struct vm_area_struct *vma;
uint32_t start = buf_page_start(addr);
uint32_t len = nr_pages << PAGE_SHIFT;
- uint32_t pfn;
+ unsigned long pfn;
int n = -1, err = 0;
- VERIFY(0 != access_ok(access ? VERIFY_WRITE : VERIFY_READ,
+ VERIFY(err, 0 != access_ok(access ? VERIFY_WRITE : VERIFY_READ,
(void __user *)start, len));
- VERIFY(0 != (vma = find_vma(current->mm, start)));
- VERIFY(((uint32_t)addr + sz) <= vma->vm_end);
+ if (err)
+ goto bail;
+ VERIFY(err, 0 != (vma = find_vma(current->mm, start)));
+ if (err)
+ goto bail;
+ VERIFY(err, ((uint32_t)addr + sz) <= vma->vm_end);
+ if (err)
+ goto bail;
n = 0;
- VERIFY(0 != (vma->vm_flags & VM_PFNMAP));
- VERIFY(0 != (vma->vm_flags & VM_PFN_AT_MMAP));
- VERIFY(nr_elems > 0);
- pfn = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
+ VERIFY(err, 0 == follow_pfn(vma, start, &pfn));
+ if (err)
+ goto bail;
+ VERIFY(err, nr_elems > 0);
+ if (err)
+ goto bail;
pages->addr = __pfn_to_phys(pfn);
pages->size = len;
n++;
diff --git a/arch/arm/mach-msm/qdsp6v2/adsprpc_shared.h b/arch/arm/mach-msm/qdsp6v2/adsprpc_shared.h
index 04b1d4a..dc6ab6f 100644
--- a/arch/arm/mach-msm/qdsp6v2/adsprpc_shared.h
+++ b/arch/arm/mach-msm/qdsp6v2/adsprpc_shared.h
@@ -60,20 +60,18 @@
#define __TOSTR__(x) __STR__(x)
#define __FILE_LINE__ __FILE__ ":" __TOSTR__(__LINE__)
-#define VERIFY(val) \
+#define VERIFY(err, val) \
do {\
VERIFY_IPRINTF(__FILE_LINE__"info: calling: " #val "\n");\
if (0 == (val)) {\
- err = err == 0 ? -1 : err;\
- VERIFY_EPRINTF(__FILE_LINE__"error: %d: " #val "\n", err);\
- goto bail;\
+ (err) = (err) == 0 ? -1 : (err);\
+ VERIFY_EPRINTF(__FILE_LINE__"error: %d: " #val "\n", (err));\
} else {\
VERIFY_IPRINTF(__FILE_LINE__"info: passed: " #val "\n");\
} \
} while (0)
#endif
-#define remote_handle_t uint32_t
#define remote_arg_t union remote_arg
struct remote_buf {
@@ -83,18 +81,18 @@
union remote_arg {
struct remote_buf buf; /* buffer info */
- remote_handle_t h; /* remote handle */
+ uint32_t h; /* remote handle */
};
struct fastrpc_ioctl_invoke {
- remote_handle_t handle; /* remote handle */
+ uint32_t handle; /* remote handle */
uint32_t sc; /* scalars describing the data */
remote_arg_t *pra; /* remote arguments list */
};
struct smq_null_invoke {
struct smq_invoke_ctx *ctx; /* invoke caller context */
- remote_handle_t handle; /* handle to invoke */
+ uint32_t handle; /* handle to invoke */
uint32_t sc; /* scalars structure describing the data */
};
diff --git a/arch/arm/mach-msm/qdsp6v2/apr.c b/arch/arm/mach-msm/qdsp6v2/apr.c
index 8ac1fea..d494069 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr.c
@@ -231,8 +231,11 @@
apr_set_q6_state(APR_SUBSYS_LOADED);
pr_debug("APR: Image is loaded, stated\n");
}
- } else
+ } else if (apr_get_q6_state() == APR_SUBSYS_LOADED) {
+ pr_debug("APR: q6 image already loaded\n");
+ } else {
pr_debug("APR: cannot load state %d\n", apr_get_q6_state());
+ }
mutex_unlock(&q6.lock);
return rc;
}
@@ -658,8 +661,8 @@
pr_debug("L-notify: Bootup started\n");
break;
case SUBSYS_AFTER_POWERUP:
- if (apr_cmpxchg_q6_state(APR_SUBSYS_DOWN, APR_SUBSYS_UP) ==
- APR_SUBSYS_DOWN)
+ if (apr_cmpxchg_q6_state(APR_SUBSYS_DOWN,
+ APR_SUBSYS_LOADED) == APR_SUBSYS_DOWN)
wake_up(&dsp_wait);
pr_debug("L-Notify: Bootup Completed\n");
break;
@@ -703,7 +706,7 @@
init_waitqueue_head(&dsp_wait);
init_waitqueue_head(&modem_wait);
subsys_notif_register_notifier("modem", &mnb);
- subsys_notif_register_notifier("lpass", &lnb);
+ subsys_notif_register_notifier(apr_get_lpass_subsys_name(), &lnb);
return ret;
}
late_initcall(apr_late_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/apr_v1.c b/arch/arm/mach-msm/qdsp6v2/apr_v1.c
index 9535968..011a73b 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr_v1.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr_v1.c
@@ -21,6 +21,8 @@
#include <mach/qdsp6v2/dsp_debug.h>
#include <mach/peripheral-loader.h>
+static const char *lpass_subsys_name = "lpass";
+
struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
uint32_t src_port, void *priv)
{
@@ -131,3 +133,8 @@
apr_set_q6_state(APR_SUBSYS_UP);
apr_set_modem_state(APR_SUBSYS_UP);
}
+
+const char *apr_get_lpass_subsys_name(void)
+{
+ return lpass_subsys_name;
+}
diff --git a/arch/arm/mach-msm/qdsp6v2/apr_v2.c b/arch/arm/mach-msm/qdsp6v2/apr_v2.c
index 1ef189f..ed494e4 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr_v2.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr_v2.c
@@ -19,6 +19,8 @@
#include <mach/qdsp6v2/apr_tal.h>
#include <mach/qdsp6v2/dsp_debug.h>
+static const char *lpass_subsys_name = "adsp";
+
struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
uint32_t src_port, void *priv)
{
@@ -48,7 +50,7 @@
pr_err("%s: adsp not up\n", __func__);
return NULL;
}
- pr_info("%s: Lpass Up\n", __func__);
+ pr_info("%s: adsp Up\n", __func__);
} else if ((dest_id == APR_DEST_MODEM) &&
(apr_get_modem_state() == APR_SUBSYS_DOWN)) {
pr_info("%s: Wait for modem to bootup\n", __func__);
@@ -125,3 +127,8 @@
apr_set_q6_state(APR_SUBSYS_DOWN);
apr_set_modem_state(APR_SUBSYS_UP);
}
+
+const char *apr_get_lpass_subsys_name(void)
+{
+ return lpass_subsys_name;
+}
diff --git a/arch/arm/mach-msm/qdsp6v2/pcm_in_proxy.c b/arch/arm/mach-msm/qdsp6v2/pcm_in_proxy.c
new file mode 100644
index 0000000..84f136a
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/pcm_in_proxy.c
@@ -0,0 +1,596 @@
+
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* only version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*/
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/msm_audio.h>
+
+#include <asm/atomic.h>
+#include <mach/debug_mm.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include <sound/q6asm.h>
+#include <sound/apr_audio.h>
+#include <linux/wakelock.h>
+#include <mach/cpuidle.h>
+
+#define MAX_BUF 4
+
+struct dma_buf {
+ uint32_t addr;
+ uint32_t v_addr;
+ uint32_t used;
+};
+struct pcm {
+ struct mutex lock;
+ struct mutex read_lock;
+ wait_queue_head_t wait;
+ spinlock_t dsp_lock;
+ struct audio_client *ac;
+ uint32_t sample_rate;
+ uint32_t channel_count;
+ uint32_t buffer_size;
+ uint32_t buffer_count;
+ uint32_t cpu_idx;
+ uint32_t dsp_idx;
+ uint32_t start;
+ uint32_t dma_addr;
+ uint32_t dma_virt;
+ struct dma_buf dma_buf[MAX_BUF];
+ atomic_t in_count;
+ atomic_t in_enabled;
+ atomic_t in_opened;
+ atomic_t in_stopped;
+ int poll_time;
+ struct hrtimer hrt;
+};
+
+static enum hrtimer_restart afe_hrtimer_callback(struct hrtimer *hrt);
+
+static enum hrtimer_restart afe_hrtimer_callback(struct hrtimer *hrt)
+{
+ struct pcm *pcm =
+ container_of(hrt, struct pcm, hrt);
+ int rc = 0;
+ if (pcm->start) {
+ if (pcm->dsp_idx == pcm->buffer_count)
+ pcm->dsp_idx = 0;
+ rc = wait_event_timeout(pcm->wait,
+ (pcm->dma_buf[pcm->dsp_idx].used == 0) ||
+ atomic_read(&pcm->in_stopped), 1 * HZ);
+ if (!rc) {
+ pr_err("%s: wait_event_timeout failed\n", __func__);
+ goto fail;
+ }
+ if (atomic_read(&pcm->in_stopped)) {
+ pr_err("%s: Driver closed - return\n", __func__);
+ return HRTIMER_NORESTART;
+ }
+ rc = afe_rt_proxy_port_read(
+ pcm->dma_buf[pcm->dsp_idx].addr,
+ pcm->buffer_size);
+ if (rc < 0) {
+ pr_err("%s afe_rt_proxy_port_read fail\n", __func__);
+ goto fail;
+ }
+ pcm->dma_buf[pcm->dsp_idx].used = 1;
+ pcm->dsp_idx++;
+ pr_debug("%s: sending frame rec to DSP: poll_time: %d\n",
+ __func__, pcm->poll_time);
+fail:
+ hrtimer_forward_now(hrt, ns_to_ktime(pcm->poll_time
+ * 1000));
+
+ return HRTIMER_RESTART;
+ } else {
+ return HRTIMER_NORESTART;
+ }
+}
+
+static void pcm_afe_callback(uint32_t opcode,
+ uint32_t token, uint32_t *payload,
+ void *priv)
+{
+ struct pcm *pcm = (struct pcm *)priv;
+ unsigned long dsp_flags;
+ uint16_t event;
+
+ if (pcm == NULL)
+ return;
+ pr_debug("%s\n", __func__);
+ spin_lock_irqsave(&pcm->dsp_lock, dsp_flags);
+ switch (opcode) {
+ case AFE_EVENT_RT_PROXY_PORT_STATUS: {
+ event = (uint16_t)((0xFFFF0000 & payload[0]) >> 0x10);
+ switch (event) {
+ case AFE_EVENT_RTPORT_START: {
+ pcm->dsp_idx = 0;
+ pcm->cpu_idx = 0;
+ pcm->poll_time = (unsigned long)
+ (((pcm->buffer_size*1000)/
+ (pcm->channel_count *
+ pcm->sample_rate * 2))*1000);
+ pr_debug("%s: poll_time:%d\n", __func__,
+ pcm->poll_time);
+ pcm->start = 1;
+ wake_up(&pcm->wait);
+ break;
+ }
+ case AFE_EVENT_RTPORT_STOP:
+ pr_debug("%s: event!=0\n", __func__);
+ pcm->start = 0;
+ atomic_set(&pcm->in_stopped, 1);
+ break;
+ case AFE_EVENT_RTPORT_LOW_WM:
+ pr_debug("%s: Underrun\n", __func__);
+ break;
+ case AFE_EVENT_RTPORT_HI_WM:
+ pr_debug("%s: Overrun\n", __func__);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case APR_BASIC_RSP_RESULT: {
+ switch (payload[0]) {
+ case AFE_SERVICE_CMD_RTPORT_RD:
+ pr_debug("%s: Read done\n", __func__);
+ atomic_inc(&pcm->in_count);
+ wake_up(&pcm->wait);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ spin_unlock_irqrestore(&pcm->dsp_lock, dsp_flags);
+}
+
+static uint32_t getbuffersize(uint32_t samplerate)
+{
+ if (samplerate == 8000)
+ return 480*8;
+ else if (samplerate == 16000)
+ return 480*16;
+ else if (samplerate == 48000)
+ return 480*48;
+ return 0;
+}
+
+static int pcm_in_open(struct inode *inode, struct file *file)
+{
+ struct pcm *pcm;
+ int rc = 0;
+
+ pr_debug("%s: pcm proxy in open session\n", __func__);
+ pcm = kzalloc(sizeof(struct pcm), GFP_KERNEL);
+ if (!pcm)
+ return -ENOMEM;
+
+ pcm->channel_count = 1;
+ pcm->sample_rate = 8000;
+ pcm->buffer_size = getbuffersize(pcm->sample_rate);
+ pcm->buffer_count = MAX_BUF;
+
+ pcm->ac = q6asm_audio_client_alloc(NULL, (void *)pcm);
+ if (!pcm->ac) {
+ pr_err("%s: Could not allocate memory\n", __func__);
+ rc = -ENOMEM;
+ goto fail;
+ }
+
+ mutex_init(&pcm->lock);
+ mutex_init(&pcm->read_lock);
+ spin_lock_init(&pcm->dsp_lock);
+ init_waitqueue_head(&pcm->wait);
+
+ hrtimer_init(&pcm->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ pcm->hrt.function = afe_hrtimer_callback;
+
+ atomic_set(&pcm->in_stopped, 0);
+ atomic_set(&pcm->in_enabled, 0);
+ atomic_set(&pcm->in_count, 0);
+ atomic_set(&pcm->in_opened, 1);
+
+ file->private_data = pcm;
+ pr_debug("%s: pcm proxy open success session id:%d\n",
+ __func__, pcm->ac->session);
+ return 0;
+fail:
+ if (pcm->ac)
+ q6asm_audio_client_free(pcm->ac);
+ kfree(pcm);
+ return rc;
+}
+
+static int pcm_in_disable(struct pcm *pcm)
+{
+ int rc = 0;
+
+ if (atomic_read(&pcm->in_opened)) {
+ atomic_set(&pcm->in_enabled, 0);
+ atomic_set(&pcm->in_opened, 0);
+ atomic_set(&pcm->in_stopped, 1);
+ wake_up(&pcm->wait);
+ }
+ return rc;
+}
+
+static int config(struct pcm *pcm)
+{
+
+ int ret = 0, i;
+ struct audio_buffer *buf;
+
+ pr_debug("%s\n", __func__);
+
+ ret = q6asm_audio_client_buf_alloc_contiguous(OUT,
+ pcm->ac,
+ pcm->buffer_size,
+ pcm->buffer_count);
+ if (ret < 0) {
+ pr_err("%s: Audio Start: Buffer Allocation failed rc = %d\n",
+ __func__, ret);
+ return -ENOMEM;
+ }
+ buf = pcm->ac->port[OUT].buf;
+
+ if (buf == NULL || buf[0].data == NULL)
+ return -ENOMEM;
+
+ memset(buf[0].data, 0, pcm->buffer_size * pcm->buffer_count);
+ pcm->dma_addr = (u32) buf[0].phys;
+ pcm->dma_virt = (u32) buf[0].data;
+
+ for (i = 0; i < pcm->buffer_count; i++) {
+ pcm->dma_buf[i].addr = (u32) (buf[i].phys);
+ pcm->dma_buf[i].v_addr = (u32) (buf[i].data);
+ pcm->dma_buf[i].used = 0;
+ }
+
+ ret = afe_register_get_events(RT_PROXY_DAI_001_TX,
+ pcm_afe_callback, pcm);
+ if (ret < 0) {
+ pr_err("%s: afe-pcm:register for events failed\n", __func__);
+ return ret;
+ }
+ ret = afe_cmd_memory_map(pcm->dma_addr,
+ pcm->buffer_size * pcm->buffer_count);
+ if (ret < 0) {
+ pr_err("%s: fail to map memory to DSP\n", __func__);
+ return ret;
+ }
+
+ pr_debug("%s:success\n", __func__);
+ return ret;
+}
+static bool is_dma_buf_avail(struct pcm *pcm)
+{
+ return (pcm->dma_buf[pcm->cpu_idx].used == 1);
+}
+static ssize_t pcm_in_read(struct file *file, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct pcm *pcm = file->private_data;
+ const char __user *start = buf;
+ int rc = 0;
+ bool rc1 = false;
+ int len = 0;
+
+ if (!atomic_read(&pcm->in_enabled))
+ return -EFAULT;
+ mutex_lock(&pcm->read_lock);
+ while (count > 0) {
+ rc = wait_event_timeout(pcm->wait,
+ (atomic_read(&pcm->in_count) ||
+ atomic_read(&pcm->in_stopped)), 2 * HZ);
+ if (!rc) {
+ pr_err("%s: wait_event_timeout failed\n", __func__);
+ goto fail;
+ }
+ if (atomic_read(&pcm->in_stopped) &&
+ !atomic_read(&pcm->in_count)) {
+ pr_err("%s: count:%d/stopped:%d failed\n", __func__,
+ atomic_read(&pcm->in_count),
+ atomic_read(&pcm->in_stopped));
+ mutex_unlock(&pcm->read_lock);
+ return 0;
+ }
+
+ rc1 = is_dma_buf_avail(pcm);
+ if (!rc1) {
+ pr_err("%s: DMA buf not ready-returning from read\n",
+ __func__);
+ goto fail;
+ }
+ if (count >= pcm->buffer_size)
+ len = pcm->buffer_size;
+ else {
+ len = count;
+ pr_err("%s: short bytesavail[%d]"\
+ "bytesrequest[%d]"\
+ "bytesrejected%d]\n",\
+ __func__, pcm->buffer_size,
+ count, (pcm->buffer_size - count));
+ }
+ if (len) {
+ if (copy_to_user(buf,
+ (char *)(pcm->dma_buf[pcm->cpu_idx].v_addr),
+ len)) {
+ pr_err("%s copy_to_user failed len[%d]\n",
+ __func__, len);
+ rc = -EFAULT;
+ goto fail;
+ }
+ count -= len;
+ buf += len;
+ }
+ atomic_dec(&pcm->in_count);
+ memset((char *)(pcm->dma_buf[pcm->cpu_idx].v_addr),
+ 0, pcm->buffer_size);
+ pcm->dma_buf[pcm->cpu_idx].used = 0;
+ wake_up(&pcm->wait);
+ pcm->cpu_idx++;
+ if (pcm->cpu_idx == pcm->buffer_count)
+ pcm->cpu_idx = 0;
+
+ }
+ rc = buf-start;
+ pr_debug("%s: pcm_in_read:rc:%d\n", __func__, rc);
+
+fail:
+ mutex_unlock(&pcm->read_lock);
+ return rc;
+}
+
+static int afe_start(struct pcm *pcm)
+{
+ union afe_port_config port_config;
+ port_config.rtproxy.num_ch =
+ pcm->channel_count;
+
+ pr_debug("%s: channel %d entered,port: %d,rate: %d\n", __func__,
+ port_config.rtproxy.num_ch, RT_PROXY_DAI_001_TX, pcm->sample_rate);
+
+ port_config.rtproxy.bitwidth = 16; /* Q6 only supports 16 */
+ port_config.rtproxy.interleaved = 1;
+ port_config.rtproxy.frame_sz = pcm->buffer_size;
+ port_config.rtproxy.jitter =
+ port_config.rtproxy.frame_sz/2;
+ port_config.rtproxy.lw_mark = 0;
+ port_config.rtproxy.hw_mark = 0;
+ port_config.rtproxy.rsvd = 0;
+ afe_open(RT_PROXY_DAI_001_TX, &port_config, pcm->sample_rate);
+ return 0;
+
+}
+
+static long pcm_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct pcm *pcm = file->private_data;
+ int rc = 0;
+
+ mutex_lock(&pcm->lock);
+ switch (cmd) {
+ case AUDIO_START: {
+ pr_debug("%s: AUDIO_START\n", __func__);
+ if (atomic_read(&pcm->in_enabled)) {
+ pr_info("%s:AUDIO_START already over\n", __func__);
+ rc = 0;
+ break;
+ }
+ rc = config(pcm);
+ if (rc) {
+ pr_err("%s: IN Configuration failed\n", __func__);
+ rc = -EFAULT;
+ break;
+ }
+ pr_debug("%s: call config done\n", __func__);
+ atomic_set(&pcm->in_enabled, 1);
+ afe_start(pcm);
+ rc = wait_event_timeout(pcm->wait,
+ ((pcm->start == 1) ||
+ atomic_read(&pcm->in_stopped)), 5 * HZ);
+ if (!rc) {
+ pr_err("%s: wait_event_timeout failed\n", __func__);
+ goto fail;
+ }
+ pr_debug("%s: afe start done\n", __func__);
+ if (atomic_read(&pcm->in_stopped)) {
+ pr_err("%s: stopped unexpected before start!!\n",
+ __func__);
+ mutex_unlock(&pcm->lock);
+ return 0;
+ }
+
+ hrtimer_start(&pcm->hrt, ns_to_ktime(0),
+ HRTIMER_MODE_REL);
+ break;
+ }
+ case AUDIO_STOP:
+ break;
+ case AUDIO_FLUSH:
+ break;
+ case AUDIO_SET_CONFIG: {
+ struct msm_audio_config config;
+
+ if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+ rc = -EFAULT;
+ break;
+ }
+ pr_debug("%s: SET_CONFIG: channel_count:%d"\
+ "sample_rate:%d\n", __func__,
+ config.channel_count,
+ config.sample_rate);
+
+ if (!config.channel_count || config.channel_count > 2) {
+ pr_err("%s: Channels(%d) not supported\n",
+ __func__, config.channel_count);
+ rc = -EINVAL;
+ break;
+ }
+
+ if (config.sample_rate != 8000 &&
+ config.sample_rate != 16000 &&
+ config.sample_rate != 48000) {
+ pr_err("%s: Sample rate(%d) not supported\n",
+ __func__, config.sample_rate);
+ rc = -EINVAL;
+ break;
+ }
+
+ pcm->sample_rate = config.sample_rate;
+ pcm->channel_count = config.channel_count;
+ pcm->buffer_size = getbuffersize(pcm->sample_rate);
+
+ pr_debug("%s: Calculated buff size %d", __func__,
+ pcm->buffer_size);
+ break;
+ }
+ case AUDIO_GET_CONFIG: {
+ struct msm_audio_config config;
+ config.buffer_size = pcm->buffer_size;
+ config.buffer_count = pcm->buffer_count;
+ config.sample_rate = pcm->sample_rate;
+ config.channel_count = pcm->channel_count;
+ config.unused[0] = 0;
+ config.unused[1] = 0;
+ config.unused[2] = 0;
+ if (copy_to_user((void *) arg, &config, sizeof(config)))
+ rc = -EFAULT;
+ break;
+ }
+ case AUDIO_PAUSE:
+ pr_debug("%s: AUDIO_PAUSE %ld\n", __func__, arg);
+ if (arg == 1) {
+ pcm->start = 0;
+ } else if (arg == 0) {
+ pcm->start = 1;
+ hrtimer_start(&pcm->hrt, ns_to_ktime(0),
+ HRTIMER_MODE_REL);
+ }
+ break;
+
+ default:
+ rc = -EINVAL;
+ break;
+ }
+fail:
+ mutex_unlock(&pcm->lock);
+ return rc;
+}
+
+static int pcm_in_release(struct inode *inode, struct file *file)
+{
+ int rc = 0;
+ struct pcm *pcm = file->private_data;
+
+ pr_debug("[%s:%s] release session id[%d]\n", __MM_FILE__,
+ __func__, pcm->ac->session);
+ mutex_lock(&pcm->lock);
+
+
+ /* remove this session from topology list */
+ auddev_cfg_tx_copp_topology(pcm->ac->session,
+ DEFAULT_COPP_TOPOLOGY);
+
+ rc = pcm_in_disable(pcm);
+ hrtimer_cancel(&pcm->hrt);
+ rc = afe_cmd_memory_unmap(pcm->dma_addr);
+ if (rc < 0)
+ pr_err("%s: AFE memory unmap failed\n", __func__);
+ rc = afe_unregister_get_events(RT_PROXY_DAI_001_TX);
+ if (rc < 0)
+ pr_err("%s: AFE unregister for events failed\n", __func__);
+
+ afe_close(RT_PROXY_DAI_001_TX);
+ pr_debug("%s: release all buffer\n", __func__);
+ q6asm_audio_client_buf_free_contiguous(OUT,
+ pcm->ac);
+ msm_clear_session_id(pcm->ac->session);
+ q6asm_audio_client_free(pcm->ac);
+ mutex_unlock(&pcm->lock);
+ mutex_destroy(&pcm->lock);
+ mutex_destroy(&pcm->read_lock);
+ kfree(pcm);
+ return rc;
+}
+
+static const struct file_operations pcm_in_proxy_fops = {
+ .owner = THIS_MODULE,
+ .open = pcm_in_open,
+ .read = pcm_in_read,
+ .release = pcm_in_release,
+ .unlocked_ioctl = pcm_in_ioctl,
+};
+
+struct miscdevice pcm_in_proxy_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_pcm_in_proxy",
+ .fops = &pcm_in_proxy_fops,
+};
+
+static int snddev_rtproxy_open(struct msm_snddev_info *dev_info)
+{
+ return 0;
+}
+
+static int snddev_rtproxy_close(struct msm_snddev_info *dev_info)
+{
+ return 0;
+}
+
+static int snddev_rtproxy_set_freq(struct msm_snddev_info *dev_info,
+ u32 req_freq)
+{
+ return 48000;
+}
+
+static int __init pcm_in_proxy_init(void)
+{
+ struct msm_snddev_info *dev_info;
+
+ dev_info = kzalloc(sizeof(struct msm_snddev_info), GFP_KERNEL);
+ if (!dev_info) {
+ pr_err("unable to allocate memeory for msm_snddev_info\n");
+ return -ENOMEM;
+ }
+ dev_info->name = "rtproxy_rx";
+ dev_info->copp_id = RT_PROXY_PORT_001_RX;
+ dev_info->acdb_id = 0;
+ dev_info->private_data = NULL;
+ dev_info->dev_ops.open = snddev_rtproxy_open;
+ dev_info->dev_ops.close = snddev_rtproxy_close;
+ dev_info->dev_ops.set_freq = snddev_rtproxy_set_freq;
+ dev_info->capability = SNDDEV_CAP_RX;
+ dev_info->opened = 0;
+ msm_snddev_register(dev_info);
+ dev_info->sample_rate = 48000;
+
+ pr_debug("%s: init done for proxy\n", __func__);
+
+ return misc_register(&pcm_in_proxy_misc);
+}
+
+device_initcall(pcm_in_proxy_init);
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
index 2189747..7966177 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -228,6 +228,7 @@
}
flush_cache_all();
+ outer_flush_all();
}
void msm_restart(char mode, const char *cmd)
diff --git a/arch/arm/mach-msm/rpm-regulator.c b/arch/arm/mach-msm/rpm-regulator.c
index 01543a2..4e5281d 100644
--- a/arch/arm/mach-msm/rpm-regulator.c
+++ b/arch/arm/mach-msm/rpm-regulator.c
@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/platform_device.h>
#include <linux/wakelock.h>
@@ -299,12 +298,9 @@
}
static bool requires_tcxo_workaround;
-static bool tcxo_workaround_noirq;
static struct clk *tcxo_handle;
static struct wake_lock tcxo_wake_lock;
static DEFINE_MUTEX(tcxo_mutex);
-/* Spin lock needed for sleep-selectable regulators. */
-static DEFINE_SPINLOCK(tcxo_noirq_lock);
static bool tcxo_is_enabled;
/*
* TCXO must be kept on for at least the duration of its warmup (4 ms);
@@ -314,19 +310,10 @@
static void tcxo_get_handle(void)
{
- int rc;
-
if (!tcxo_handle) {
tcxo_handle = clk_get_sys("rpm-regulator", "vref_buff");
- if (IS_ERR(tcxo_handle)) {
+ if (IS_ERR(tcxo_handle))
tcxo_handle = NULL;
- } else {
- rc = clk_prepare(tcxo_handle);
- if (rc) {
- clk_put(tcxo_handle);
- tcxo_handle = NULL;
- }
- }
}
}
@@ -342,7 +329,7 @@
int rc;
if (tcxo_handle && !tcxo_is_enabled) {
- rc = clk_enable(tcxo_handle);
+ rc = clk_prepare_enable(tcxo_handle);
if (!rc) {
tcxo_is_enabled = true;
wake_lock(&tcxo_wake_lock);
@@ -355,21 +342,13 @@
static void tcxo_delayed_disable_work(struct work_struct *work)
{
- unsigned long flags = 0;
+ mutex_lock(&tcxo_mutex);
- if (tcxo_workaround_noirq)
- spin_lock_irqsave(&tcxo_noirq_lock, flags);
- else
- mutex_lock(&tcxo_mutex);
-
- clk_disable(tcxo_handle);
+ clk_disable_unprepare(tcxo_handle);
tcxo_is_enabled = false;
wake_unlock(&tcxo_wake_lock);
- if (tcxo_workaround_noirq)
- spin_unlock_irqrestore(&tcxo_noirq_lock, flags);
- else
- mutex_unlock(&tcxo_mutex);
+ mutex_unlock(&tcxo_mutex);
}
static DECLARE_DELAYED_WORK(tcxo_disable_work, tcxo_delayed_disable_work);
@@ -387,8 +366,8 @@
msecs_to_jiffies(TCXO_WARMUP_TIME_MS) + 1);
}
-/* Spin lock needed for sleep-selectable regulators. */
-static DEFINE_SPINLOCK(rpm_noirq_lock);
+/* Mutex lock needed for sleep-selectable regulators. */
+static DEFINE_MUTEX(rpm_sleep_sel_lock);
static int voltage_from_req(struct vreg *vreg)
{
@@ -421,7 +400,6 @@
{
struct msm_rpm_iv_pair *prev_req;
int rc = 0, max_uV_vote = 0;
- unsigned long flags = 0;
bool tcxo_enabled = false;
bool voltage_increased = false;
unsigned prev0, prev1;
@@ -470,17 +448,19 @@
if (requires_tcxo_workaround && vreg->requires_cxo
&& (set == MSM_RPM_CTX_SET_0)
&& (GET_PART(vreg, uV) > GET_PART_PREV_ACT(vreg, uV))) {
+ mutex_lock(&tcxo_mutex);
+ if (!tcxo_handle)
+ tcxo_get_handle();
voltage_increased = true;
- spin_lock_irqsave(&tcxo_noirq_lock, flags);
tcxo_enabled = tcxo_enable();
}
- rc = msm_rpmrs_set_noirq(set, vreg->req, cnt);
+ rc = msm_rpmrs_set(set, vreg->req, cnt);
if (rc) {
vreg->req[0].value = prev0;
vreg->req[1].value = prev1;
- vreg_err(vreg, "msm_rpmrs_set_noirq failed - "
+ vreg_err(vreg, "msm_rpmrs_set failed - "
"set=%s, id=%d, rc=%d\n",
(set == MSM_RPM_CTX_SET_0 ? "active" : "sleep"),
vreg->req[0].id, rc);
@@ -502,7 +482,7 @@
if (voltage_increased) {
if (tcxo_enabled)
tcxo_delayed_disable();
- spin_unlock_irqrestore(&tcxo_noirq_lock, flags);
+ mutex_unlock(&tcxo_mutex);
}
} else if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_DUPLICATE) {
rpm_regulator_duplicate(vreg, set, cnt);
@@ -511,19 +491,18 @@
return rc;
}
-static int vreg_set_noirq(struct vreg *vreg, enum rpm_vreg_voter voter,
+static int vreg_set_sleep_sel(struct vreg *vreg, enum rpm_vreg_voter voter,
int sleep, unsigned mask0, unsigned val0,
unsigned mask1, unsigned val1, unsigned cnt,
int update_voltage)
{
unsigned int s_mask[2] = {mask0, mask1}, s_val[2] = {val0, val1};
- unsigned long flags;
int rc;
if (voter < 0 || voter >= RPM_VREG_VOTER_COUNT)
return -EINVAL;
- spin_lock_irqsave(&rpm_noirq_lock, flags);
+ mutex_lock(&rpm_sleep_sel_lock);
/*
* Send sleep set request first so that subsequent set_mode, etc calls
@@ -559,7 +538,7 @@
rc = vreg_send_request(vreg, voter, MSM_RPM_CTX_SET_0, mask0, val0,
mask1, val1, cnt, update_voltage);
- spin_unlock_irqrestore(&rpm_noirq_lock, flags);
+ mutex_unlock(&rpm_sleep_sel_lock);
return rc;
}
@@ -575,10 +554,8 @@
* Returns 0 on success or errno.
*
* This function is used to vote for the voltage of a regulator without
- * using the regulator framework. It is needed by consumers which hold spin
- * locks or have interrupts disabled because the regulator framework can sleep.
- * It is also needed by consumers which wish to only vote for active set
- * regulator voltage.
+ * using the regulator framework. It is needed for consumers which wish to only
+ * vote for active set regulator voltage.
*
* If sleep_also == 0, then a sleep-set value of 0V will be voted for.
*
@@ -693,10 +670,10 @@
= vreg->part->enable_state.mask;
}
- rc = vreg_set_noirq(vreg, voter, sleep_also, mask[0], val[0], mask[1],
- val[1], vreg->part->request_len, 1);
+ rc = vreg_set_sleep_sel(vreg, voter, sleep_also, mask[0], val[0],
+ mask[1], val[1], vreg->part->request_len, 1);
if (rc)
- vreg_err(vreg, "vreg_set_noirq failed, rc=%d\n", rc);
+ vreg_err(vreg, "vreg_set_sleep_sel failed, rc=%d\n", rc);
return rc;
}
@@ -743,10 +720,10 @@
val[vreg->part->freq.word] = freq << vreg->part->freq.shift;
mask[vreg->part->freq.word] = vreg->part->freq.mask;
- rc = vreg_set_noirq(vreg, RPM_VREG_VOTER_REG_FRAMEWORK, 1, mask[0],
+ rc = vreg_set_sleep_sel(vreg, RPM_VREG_VOTER_REG_FRAMEWORK, 1, mask[0],
val[0], mask[1], val[1], vreg->part->request_len, 0);
if (rc)
- vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
+ vreg_err(vreg, "vreg_set_sleep_sel failed, rc=%d\n", rc);
return rc;
}
@@ -1018,10 +995,8 @@
static int vreg_store(struct vreg *vreg, unsigned mask0, unsigned val0,
unsigned mask1, unsigned val1)
{
- unsigned long flags = 0;
-
if (vreg->pdata.sleep_selectable)
- spin_lock_irqsave(&rpm_noirq_lock, flags);
+ mutex_lock(&rpm_sleep_sel_lock);
vreg->req[0].value &= ~mask0;
vreg->req[0].value |= val0 & mask0;
@@ -1030,7 +1005,7 @@
vreg->req[1].value |= val1 & mask1;
if (vreg->pdata.sleep_selectable)
- spin_unlock_irqrestore(&rpm_noirq_lock, flags);
+ mutex_unlock(&rpm_sleep_sel_lock);
return 0;
}
@@ -1039,7 +1014,6 @@
unsigned mask1, unsigned val1, unsigned cnt)
{
unsigned prev0 = 0, prev1 = 0;
- unsigned long flags = 0;
bool tcxo_enabled = false;
bool voltage_increased = false;
int rc;
@@ -1049,7 +1023,7 @@
* just the active set values.
*/
if (vreg->pdata.sleep_selectable)
- return vreg_set_noirq(vreg, RPM_VREG_VOTER_REG_FRAMEWORK, 1,
+ return vreg_set_sleep_sel(vreg, RPM_VREG_VOTER_REG_FRAMEWORK, 1,
mask0, val0, mask1, val1, cnt, 1);
prev0 = vreg->req[0].value;
@@ -1071,21 +1045,14 @@
/* Enable CXO clock if necessary for TCXO workaround. */
if (requires_tcxo_workaround && vreg->requires_cxo
&& (GET_PART(vreg, uV) > GET_PART_PREV_ACT(vreg, uV))) {
+ mutex_lock(&tcxo_mutex);
if (!tcxo_handle)
tcxo_get_handle();
- if (tcxo_workaround_noirq)
- spin_lock_irqsave(&tcxo_noirq_lock, flags);
- else
- mutex_lock(&tcxo_mutex);
-
voltage_increased = true;
tcxo_enabled = tcxo_enable();
}
- if (voltage_increased && tcxo_workaround_noirq)
- rc = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_0, vreg->req, cnt);
- else
- rc = msm_rpm_set(MSM_RPM_CTX_SET_0, vreg->req, cnt);
+ rc = msm_rpm_set(MSM_RPM_CTX_SET_0, vreg->req, cnt);
if (rc) {
vreg->req[0].value = prev0;
@@ -1107,11 +1074,7 @@
if (voltage_increased) {
if (tcxo_enabled)
tcxo_delayed_disable();
-
- if (tcxo_workaround_noirq)
- spin_unlock_irqrestore(&tcxo_noirq_lock, flags);
- else
- mutex_unlock(&tcxo_mutex);
+ mutex_unlock(&tcxo_mutex);
}
return rc;
@@ -1794,7 +1757,6 @@
struct rpm_regulator_platform_data *platform_data;
static struct rpm_regulator_consumer_mapping *prev_consumer_map;
static int prev_consumer_map_len;
- struct vreg *vreg;
int rc = 0;
int i, id;
@@ -1880,18 +1842,6 @@
"rpm_regulator_tcxo");
}
- if (requires_tcxo_workaround && !tcxo_workaround_noirq) {
- for (i = 0; i < platform_data->num_regulators; i++) {
- vreg = rpm_vreg_get_vreg(
- platform_data->init_data[i].id);
- if (vreg && vreg->requires_cxo
- && platform_data->init_data[i].sleep_selectable) {
- tcxo_workaround_noirq = true;
- break;
- }
- }
- }
-
/* Initialize all of the regulators listed in the platform data. */
for (i = 0; i < platform_data->num_regulators; i++) {
rc = rpm_vreg_init_regulator(&platform_data->init_data[i],
diff --git a/arch/arm/mach-msm/rpm_master_stat.c b/arch/arm/mach-msm/rpm_master_stat.c
new file mode 100644
index 0000000..4dcf5eb
--- /dev/null
+++ b/arch/arm/mach-msm/rpm_master_stat.c
@@ -0,0 +1,247 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <asm/uaccess.h>
+
+#include <mach/msm_iomap.h>
+#include "rpm_stats.h"
+#define MSG_RAM_SIZE_PER_MASTER 32
+
+enum {
+ NUMSHUTDOWNS,
+ ACTIVECORES,
+ MASTER_ID_MAX,
+};
+
+static char *msm_rpm_master_stats_id_labels[MASTER_ID_MAX] = {
+ [NUMSHUTDOWNS] = "num_shutdowns",
+ [ACTIVECORES] = "active_cores",
+};
+
+
+struct msm_rpm_master_stats {
+ unsigned long numshutdowns;
+ unsigned long active_cores;
+};
+
+struct msm_rpm_master_stats_private_data {
+ void __iomem *reg_base;
+ u32 len;
+ char **master_names;
+ u32 nomasters;
+ char buf[256];
+ struct msm_rpm_master_stats_platform_data *platform_data;
+};
+
+static int msm_rpm_master_stats_file_close(struct inode *inode,
+ struct file *file)
+{
+ struct msm_rpm_master_stats_private_data *private = file->private_data;
+
+ if (private->reg_base)
+ iounmap(private->reg_base);
+ kfree(file->private_data);
+
+ return 0;
+}
+
+static int msm_rpm_master_copy_stats(
+ struct msm_rpm_master_stats_private_data *pdata)
+{
+ struct msm_rpm_master_stats record;
+ static int nomasters;
+ int count;
+ static DEFINE_MUTEX(msm_rpm_master_stats_mutex);
+ int j = 0;
+
+ mutex_lock(&msm_rpm_master_stats_mutex);
+ /*
+ * iterrate possible nomasters times.
+ * 8960, 8064 have 5 masters.
+ * 8930 has 4 masters.
+ * 9x15 has 3 masters.
+ */
+ if (nomasters > pdata->nomasters - 1) {
+ nomasters = 0;
+ mutex_unlock(&msm_rpm_master_stats_mutex);
+ return 0;
+ }
+
+ record.numshutdowns = readl_relaxed(pdata->reg_base +
+ (nomasters * MSG_RAM_SIZE_PER_MASTER));
+ record.active_cores = readl_relaxed(pdata->reg_base +
+ (nomasters * MSG_RAM_SIZE_PER_MASTER + 4));
+
+ count = snprintf(pdata->buf, sizeof(pdata->buf),
+ "%s\n\t%s:%lu\n\t%s:%lu\n",
+ pdata->master_names[nomasters],
+ msm_rpm_master_stats_id_labels[0],
+ record.numshutdowns,
+ msm_rpm_master_stats_id_labels[1],
+ record.active_cores);
+
+ j = find_first_bit(&record.active_cores, BITS_PER_LONG);
+ while (j < BITS_PER_LONG) {
+ count += snprintf(pdata->buf + count,
+ sizeof(pdata->buf) - count,
+ "\t\tcore%d\n", j);
+ j = find_next_bit(&record.active_cores,
+ BITS_PER_LONG, j + 1);
+ }
+
+
+ nomasters++;
+ mutex_unlock(&msm_rpm_master_stats_mutex);
+ return count;
+}
+
+static int msm_rpm_master_stats_file_read(struct file *file, char __user *bufu,
+ size_t count, loff_t *ppos)
+{
+ struct msm_rpm_master_stats_private_data *prvdata;
+ struct msm_rpm_master_stats_platform_data *pdata;
+
+ prvdata = file->private_data;
+ if (!prvdata)
+ return -EINVAL;
+
+ pdata = prvdata->platform_data;
+ if (!pdata)
+ return -EINVAL;
+
+ if (!bufu || count < 0)
+ return -EINVAL;
+
+ if ((*ppos <= pdata->phys_size)) {
+ prvdata->len = msm_rpm_master_copy_stats(prvdata);
+ *ppos = 0;
+ }
+
+ return simple_read_from_buffer(bufu, count, ppos,
+ prvdata->buf, prvdata->len);
+}
+
+static int msm_rpm_master_stats_file_open(struct inode *inode,
+ struct file *file)
+{
+ struct msm_rpm_master_stats_private_data *prvdata;
+ struct msm_rpm_master_stats_platform_data *pdata;
+
+ pdata = inode->i_private;
+
+ file->private_data =
+ kmalloc(sizeof(struct msm_rpm_master_stats_private_data),
+ GFP_KERNEL);
+
+ if (!file->private_data)
+ return -ENOMEM;
+ prvdata = file->private_data;
+
+ prvdata->reg_base = ioremap(pdata->phys_addr_base,
+ pdata->phys_size);
+ if (!prvdata->reg_base) {
+ kfree(file->private_data);
+ prvdata = NULL;
+ pr_err("%s: ERROR could not ioremap start=%p, len=%u\n",
+ __func__, (void *)pdata->phys_addr_base,
+ pdata->phys_size);
+ return -EBUSY;
+ }
+
+ prvdata->len = 0;
+ prvdata->nomasters = pdata->nomasters;
+ prvdata->master_names = pdata->masters;
+ prvdata->platform_data = pdata;
+ return 0;
+}
+
+static const struct file_operations msm_rpm_master_stats_fops = {
+ .owner = THIS_MODULE,
+ .open = msm_rpm_master_stats_file_open,
+ .read = msm_rpm_master_stats_file_read,
+ .release = msm_rpm_master_stats_file_close,
+ .llseek = no_llseek,
+};
+
+static int __devinit msm_rpm_master_stats_probe(struct platform_device *pdev)
+{
+ struct dentry *dent;
+ struct msm_rpm_master_stats_platform_data *pdata;
+ struct resource *res;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata)
+ return -EINVAL;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pdata->phys_addr_base = res->start;
+ pdata->phys_size = resource_size(res);
+
+ dent = debugfs_create_file("rpm_master_stats", S_IRUGO, NULL,
+ pdev->dev.platform_data, &msm_rpm_master_stats_fops);
+
+ if (!dent) {
+ pr_err("%s: ERROR debugfs_create_file failed\n", __func__);
+ return -ENOMEM;
+ }
+ platform_set_drvdata(pdev, dent);
+ return 0;
+}
+
+static int __devexit msm_rpm_master_stats_remove(struct platform_device *pdev)
+{
+ struct dentry *dent;
+
+ dent = platform_get_drvdata(pdev);
+ debugfs_remove(dent);
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+static struct platform_driver msm_rpm_master_stats_driver = {
+ .probe = msm_rpm_master_stats_probe,
+ .remove = __devexit_p(msm_rpm_master_stats_remove),
+ .driver = {
+ .name = "msm_rpm_master_stat",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_rpm_master_stats_init(void)
+{
+ return platform_driver_register(&msm_rpm_master_stats_driver);
+}
+
+static void __exit msm_rpm_master_stats_exit(void)
+{
+ platform_driver_unregister(&msm_rpm_master_stats_driver);
+}
+
+module_init(msm_rpm_master_stats_init);
+module_exit(msm_rpm_master_stats_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM RPM Master Statistics driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:msm_master_stat_log");
diff --git a/arch/arm/mach-msm/scm-pas.c b/arch/arm/mach-msm/scm-pas.c
index 43436e5..55ae2f8 100644
--- a/arch/arm/mach-msm/scm-pas.c
+++ b/arch/arm/mach-msm/scm-pas.c
@@ -204,11 +204,7 @@
}
}
- /* TODO : Remove once bus scaling driver is in place */
- if (!cpu_is_msm8226())
- scm_perf_client = msm_bus_scale_register_client(
- &scm_pas_bus_pdata);
-
+ scm_perf_client = msm_bus_scale_register_client(&scm_pas_bus_pdata);
if (!scm_perf_client)
pr_warn("unable to register bus client\n");
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index cb9fc76..bb4da0f 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -38,6 +38,8 @@
static unsigned int l2x0_ways;
static unsigned long sync_reg_offset = L2X0_CACHE_SYNC;
static void pl310_save(void);
+static void pl310_resume(void);
+static void l2x0_resume(void);
static inline bool is_pl310_rev(int rev)
{
@@ -378,15 +380,18 @@
sync_reg_offset = L2X0_DUMMY_REG;
#endif
outer_cache.set_debug = pl310_set_debug;
+ outer_cache.resume = pl310_resume;
break;
case L2X0_CACHE_ID_PART_L210:
l2x0_ways = (aux >> 13) & 0xf;
type = "L210";
+ outer_cache.resume = l2x0_resume;
break;
default:
/* Assume unknown chips have 8 ways */
l2x0_ways = 8;
type = "L2x0 series";
+ outer_cache.resume = l2x0_resume;
break;
}
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 7c0c0b9..5cd5ce9 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -35,6 +35,8 @@
unsigned int dci_max_clients = 10;
unsigned char dci_cumulative_log_mask[DCI_LOG_MASK_SIZE];
unsigned char dci_cumulative_event_mask[DCI_EVENT_MASK_SIZE];
+struct mutex dci_log_mask_mutex;
+struct mutex dci_event_mask_mutex;
#define DCI_CHK_CAPACITY(entry, new_data_len) \
((entry->data_len + new_data_len > entry->total_capacity) ? 1 : 0) \
@@ -91,14 +93,15 @@
read_bytes += 5 + dci_pkt_len;
buf += 5 + dci_pkt_len; /* advance to next DCI pkt */
}
- driver->in_busy_dci = 1;
/* wake up all sleeping DCI clients which have some data */
for (i = 0; i < MAX_DCI_CLIENTS; i++)
if (driver->dci_client_tbl[i].client &&
- driver->dci_client_tbl[i].data_len)
+ driver->dci_client_tbl[i].data_len) {
+ driver->in_busy_dci = 1;
diag_update_sleeping_process(
driver->dci_client_tbl[i].client->tgid,
DCI_DATA_TYPE);
+ }
}
}
@@ -224,6 +227,8 @@
dropped_events++;
return;
}
+ driver->dci_client_tbl[i].
+ received_events++;
*(int *)(entry->dci_data+
entry->data_len) = DCI_EVENT_TYPE;
memcpy(entry->dci_data+
@@ -281,6 +286,7 @@
dropped_logs++;
return;
}
+ driver->dci_client_tbl[i].received_logs++;
*(int *)(entry->dci_data+entry->data_len) =
DCI_LOG_TYPE;
memcpy(entry->dci_data+entry->data_len+4, buf+4,
@@ -378,14 +384,6 @@
}
}
mutex_lock(&driver->dci_mutex);
- if (new_dci_client)
- driver->num_dci_client++;
- if (driver->num_dci_client > MAX_DCI_CLIENTS) {
- pr_info("diag: Max DCI Client limit reached\n");
- driver->num_dci_client--;
- mutex_unlock(&driver->dci_mutex);
- return ret;
- }
/* Make an entry in kernel DCI table */
driver->dci_tag++;
for (i = 0; i < dci_max_reg; i++) {
@@ -483,7 +481,7 @@
temp += 4;
head_log_mask_ptr = driver->dci_client_tbl[i].dci_log_mask;
- pr_info("diag: head of dci log mask %p\n", head_log_mask_ptr);
+ pr_debug("diag: head of dci log mask %p\n", head_log_mask_ptr);
count = 0; /* iterator for extracting log codes */
while (count < num_codes) {
log_code = *(uint16_t *)temp;
@@ -500,11 +498,11 @@
while (log_mask_ptr) {
if (*log_mask_ptr == equip_id) {
found = 1;
- pr_info("diag: find equip id = %x at %p\n",
+ pr_debug("diag: find equip id = %x at %p\n",
equip_id, log_mask_ptr);
break;
} else {
- pr_info("diag: did not find equip id = %x at %p\n",
+ pr_debug("diag: did not find equip id = %x at %p\n",
equip_id, log_mask_ptr);
log_mask_ptr += 514;
}
@@ -583,9 +581,11 @@
uint8_t *update_ptr = dci_cumulative_event_mask;
uint8_t *event_mask_ptr;
+ mutex_lock(&dci_event_mask_mutex);
event_mask_ptr = driver->dci_client_tbl[client_index].dci_event_mask;
for (i = 0; i < DCI_EVENT_MASK_SIZE; i++)
*(update_ptr+i) |= *(event_mask_ptr+i);
+ mutex_unlock(&dci_event_mask_mutex);
}
void diag_send_dci_event_mask(smd_channel_t *ch)
@@ -631,6 +631,7 @@
uint8_t *log_mask_ptr =
driver->dci_client_tbl[client_index].dci_log_mask;
+ mutex_lock(&dci_log_mask_mutex);
*update_ptr = 0; /* add first equip id */
/* skip the first equip id */
update_ptr++; log_mask_ptr++;
@@ -644,6 +645,7 @@
update_ptr++;
log_mask_ptr++;
}
+ mutex_unlock(&dci_log_mask_mutex);
}
void diag_send_dci_log_mask(smd_channel_t *ch)
@@ -743,6 +745,8 @@
driver->num_dci_client = 0;
driver->in_busy_dci = 0;
mutex_init(&driver->dci_mutex);
+ mutex_init(&dci_log_mask_mutex);
+ mutex_init(&dci_event_mask_mutex);
if (driver->buf_in_dci == NULL) {
driver->buf_in_dci = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
if (driver->buf_in_dci == NULL)
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 97a285c..afcabcc 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -53,6 +53,17 @@
int total_capacity;
int dropped_logs;
int dropped_events;
+ int received_logs;
+ int received_events;
+};
+
+/* This is used for DCI health stats */
+struct diag_dci_health_stats {
+ int dropped_logs;
+ int dropped_events;
+ int received_logs;
+ int received_events;
+ int reset_status;
};
enum {
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index a37260b..28d0565 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -257,6 +257,7 @@
int mask_check;
int logging_process_id;
struct task_struct *socket_process;
+ struct task_struct *callback_process;
#ifdef CONFIG_DIAG_SDIO_PIPE
unsigned char *buf_in_sdio;
unsigned char *usb_buf_mdm_out;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index c29a1d3f..92efd94 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -246,22 +246,32 @@
int i = 0;
struct diagchar_priv *diagpriv_data = file->private_data;
+ pr_debug("diag: process exit %s\n", current->comm);
if (!(file->private_data)) {
pr_alert("diag: Invalid file pointer");
return -ENOMEM;
}
-
- /* clean up any DCI registrations for this client
+ /* clean up any DCI registrations, if this is a DCI client
* This will specially help in case of ungraceful exit of any DCI client
* This call will remove any pending registrations of such client
*/
- diagchar_ioctl(NULL, DIAG_IOCTL_DCI_DEINIT, 0);
-
+ for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+ if (driver->dci_client_tbl[i].client &&
+ driver->dci_client_tbl[i].client->tgid ==
+ current->tgid) {
+ diagchar_ioctl(NULL, DIAG_IOCTL_DCI_DEINIT, 0);
+ break;
+ }
+ }
/* If the exiting process is the socket process */
if (driver->socket_process &&
(driver->socket_process->tgid == current->tgid)) {
driver->socket_process = NULL;
}
+ if (driver->callback_process &&
+ (driver->callback_process->tgid == current->tgid)) {
+ driver->callback_process = NULL;
+ }
#ifdef CONFIG_DIAG_OVER_USB
/* If the SD logging process exits, change logging to USB mode */
@@ -377,7 +387,9 @@
int success = -1;
void *temp_buf;
uint16_t support_list = 0;
- struct diag_dci_client_tbl *notify_params;
+ struct diag_dci_client_tbl *params =
+ kzalloc(sizeof(struct diag_dci_client_tbl), GFP_KERNEL);
+ struct diag_dci_health_stats stats;
int status;
if (iocmd == DIAG_IOCTL_COMMAND_REG) {
@@ -451,8 +463,12 @@
return DIAG_DCI_NO_REG;
if (driver->num_dci_client >= MAX_DCI_CLIENTS)
return DIAG_DCI_NO_REG;
- notify_params = (struct diag_dci_client_tbl *) ioarg;
+ if (copy_from_user(params, (void *)ioarg,
+ sizeof(struct diag_dci_client_tbl)))
+ return -EFAULT;
mutex_lock(&driver->dci_mutex);
+ if (!(driver->num_dci_client))
+ driver->in_busy_dci = 0;
driver->num_dci_client++;
pr_debug("diag: id = %d\n", driver->dci_client_id);
driver->dci_client_id++;
@@ -460,9 +476,9 @@
if (driver->dci_client_tbl[i].client == NULL) {
driver->dci_client_tbl[i].client = current;
driver->dci_client_tbl[i].list =
- notify_params->list;
+ params->list;
driver->dci_client_tbl[i].signal_type =
- notify_params->signal_type;
+ params->signal_type;
create_dci_log_mask_tbl(driver->
dci_client_tbl[i].dci_log_mask);
create_dci_event_mask_tbl(driver->
@@ -474,6 +490,8 @@
IN_BUF_SIZE;
driver->dci_client_tbl[i].dropped_logs = 0;
driver->dci_client_tbl[i].dropped_events = 0;
+ driver->dci_client_tbl[i].received_logs = 0;
+ driver->dci_client_tbl[i].received_events = 0;
break;
}
}
@@ -483,32 +501,52 @@
success = -1;
/* Delete this process from DCI table */
mutex_lock(&driver->dci_mutex);
- for (i = 0; i < dci_max_reg; i++) {
- if (driver->req_tracking_tbl[i].pid == current->tgid) {
- pr_debug("diag: delete %d\n", current->tgid);
+ for (i = 0; i < dci_max_reg; i++)
+ if (driver->req_tracking_tbl[i].pid == current->tgid)
driver->req_tracking_tbl[i].pid = 0;
- success = i;
- }
- }
for (i = 0; i < MAX_DCI_CLIENTS; i++) {
- if (driver->dci_client_tbl[i].client == current) {
+ if (driver->dci_client_tbl[i].client &&
+ driver->dci_client_tbl[i].client->tgid ==
+ current->tgid) {
driver->dci_client_tbl[i].client = NULL;
+ success = i;
break;
}
}
- /* if any registrations were deleted successfully OR a valid
- client_id was sent in DEINIT call , then its DCI client */
- if (success >= 0 || ioarg)
+ if (success >= 0)
driver->num_dci_client--;
- driver->num_dci_client--;
mutex_unlock(&driver->dci_mutex);
- pr_debug("diag: complete deleting registrations\n");
return success;
} else if (iocmd == DIAG_IOCTL_DCI_SUPPORT) {
if (driver->ch_dci)
support_list = support_list | DIAG_CON_MPSS;
*(uint16_t *)ioarg = support_list;
return DIAG_DCI_NO_ERROR;
+ } else if (iocmd == DIAG_IOCTL_DCI_HEALTH_STATS) {
+ if (copy_from_user(&stats, (void *)ioarg,
+ sizeof(struct diag_dci_health_stats)))
+ return -EFAULT;
+ for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+ params = &(driver->dci_client_tbl[i]);
+ if (params->client &&
+ params->client->tgid == current->tgid) {
+ stats.dropped_logs = params->dropped_logs;
+ stats.dropped_events = params->dropped_events;
+ stats.received_logs = params->received_logs;
+ stats.received_events = params->received_events;
+ if (stats.reset_status) {
+ params->dropped_logs = 0;
+ params->dropped_events = 0;
+ params->received_logs = 0;
+ params->received_events = 0;
+ }
+ break;
+ }
+ }
+ if (copy_to_user((void *)ioarg, &stats,
+ sizeof(struct diag_dci_health_stats)))
+ return -EFAULT;
+ return DIAG_DCI_NO_ERROR;
} else if (iocmd == DIAG_IOCTL_LSM_DEINIT) {
for (i = 0; i < driver->num_clients; i++)
if (driver->client_map[i].pid == current->tgid)
@@ -522,6 +560,11 @@
mutex_lock(&driver->diagchar_mutex);
temp = driver->logging_mode;
driver->logging_mode = (int)ioarg;
+ if (temp == driver->logging_mode) {
+ mutex_unlock(&driver->diagchar_mutex);
+ pr_alert("diag: forbidden logging change requested\n");
+ return 0;
+ }
if (driver->logging_mode == MEMORY_DEVICE_MODE) {
diag_clear_hsic_tbl();
driver->mask_check = 1;
@@ -540,17 +583,17 @@
}
}
}
- if (driver->logging_mode == UART_MODE) {
+ if (driver->logging_mode == UART_MODE ||
+ driver->logging_mode == SOCKET_MODE ||
+ driver->logging_mode == CALLBACK_MODE) {
diag_clear_hsic_tbl();
driver->mask_check = 0;
driver->logging_mode = MEMORY_DEVICE_MODE;
}
- if (driver->logging_mode == SOCKET_MODE) {
- diag_clear_hsic_tbl();
+ if (driver->logging_mode == SOCKET_MODE)
driver->socket_process = current;
- driver->mask_check = 0;
- driver->logging_mode = MEMORY_DEVICE_MODE;
- }
+ if (driver->logging_mode == CALLBACK_MODE)
+ driver->callback_process = current;
driver->logging_process_id = current->tgid;
mutex_unlock(&driver->diagchar_mutex);
if (temp == MEMORY_DEVICE_MODE && driver->logging_mode
@@ -680,7 +723,7 @@
driver->data_ready[index]);
mutex_lock(&driver->diagchar_mutex);
- if ((driver->data_ready[index] & USER_SPACE_LOG_TYPE) && (driver->
+ if ((driver->data_ready[index] & USER_SPACE_DATA_TYPE) && (driver->
logging_mode == MEMORY_DEVICE_MODE)) {
#ifdef CONFIG_DIAG_BRIDGE_CODE
unsigned long spin_lock_flags;
@@ -689,7 +732,7 @@
pr_debug("diag: process woken up\n");
/*Copy the type of data being passed*/
- data_type = driver->data_ready[index] & USER_SPACE_LOG_TYPE;
+ data_type = driver->data_ready[index] & USER_SPACE_DATA_TYPE;
COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
/* place holder for number of data field */
ret += 4;
@@ -892,7 +935,7 @@
/* copy number of data fields */
COPY_USER_SPACE_OR_EXIT(buf+4, num_data, 4);
ret -= 4;
- driver->data_ready[index] ^= USER_SPACE_LOG_TYPE;
+ driver->data_ready[index] ^= USER_SPACE_DATA_TYPE;
if (driver->ch)
queue_work(driver->diag_wq,
&(driver->diag_read_smd_work));
@@ -909,10 +952,10 @@
#endif
APPEND_DEBUG('n');
goto exit;
- } else if (driver->data_ready[index] & USER_SPACE_LOG_TYPE) {
+ } else if (driver->data_ready[index] & USER_SPACE_DATA_TYPE) {
/* In case, the thread wakes up and the logging mode is
not memory device any more, the condition needs to be cleared */
- driver->data_ready[index] ^= USER_SPACE_LOG_TYPE;
+ driver->data_ready[index] ^= USER_SPACE_DATA_TYPE;
}
if (driver->data_ready[index] & DEINIT_TYPE) {
@@ -1026,7 +1069,7 @@
payload_size);
return err;
}
- if (pkt_type == USER_SPACE_LOG_TYPE) {
+ if (pkt_type == USER_SPACE_DATA_TYPE) {
err = copy_from_user(driver->user_space_data, buf + 4,
payload_size);
/* Check masks for On-Device logging */
@@ -1409,6 +1452,7 @@
driver->num_clients = max_clients;
driver->logging_mode = USB_MODE;
driver->socket_process = NULL;
+ driver->callback_process = NULL;
driver->mask_check = 0;
mutex_init(&driver->diagchar_mutex);
init_waitqueue_head(&driver->wait_q);
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index d27ebcf..978b63b 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -212,8 +212,8 @@
* have their data read/logged. Detect and remedy this
* situation.
*/
- if ((driver->data_ready[i] & USER_SPACE_LOG_TYPE) == 0) {
- driver->data_ready[i] |= USER_SPACE_LOG_TYPE;
+ if ((driver->data_ready[i] & USER_SPACE_DATA_TYPE) == 0) {
+ driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
pr_debug("diag: Force wakeup of logging process\n");
wake_up_interruptible(&driver->wait_q);
}
@@ -357,7 +357,7 @@
driver->logging_process_id)
break;
if (i < driver->num_clients) {
- driver->data_ready[i] |= USER_SPACE_LOG_TYPE;
+ driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
pr_debug("diag: wake up logging process\n");
wake_up_interruptible(&driver->wait_q);
} else
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 8a9567b..1312448 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -382,7 +382,7 @@
break;
case QCE_MODE_XTS:
- if (creq->encklen == AES128_KEY_SIZE)
+ if (creq->encklen/2 == AES128_KEY_SIZE)
*cmdlistinfo = &cmdlistptr->cipher_aes_128_xts;
else
*cmdlistinfo = &cmdlistptr->cipher_aes_256_xts;
@@ -767,15 +767,30 @@
if ((pce_dev->mode == QCE_MODE_CTR) ||
(pce_dev->mode == QCE_MODE_XTS)) {
uint32_t num_blk = 0;
- uint32_t cntr_iv = 0;
+ uint32_t cntr_iv3 = 0;
+ unsigned long long cntr_iv64 = 0;
+ unsigned char *b = (unsigned char *)(&cntr_iv3);
memcpy(iv, areq->info, sizeof(iv));
- if (pce_dev->mode == QCE_MODE_CTR)
+ if (pce_dev->mode != QCE_MODE_XTS)
num_blk = areq->nbytes/16;
- cntr_iv = (u32)(((u32)(*(iv + 14))) << 8) |
- (u32)(*(iv + 15));
- *(iv + 14) = (char)((cntr_iv + num_blk) >> 8);
- *(iv + 15) = (char)((cntr_iv + num_blk) & 0xFF);
+ else
+ num_blk = 1;
+ cntr_iv3 = ((*(iv + 12) << 24) & 0xff000000) |
+ (((*(iv + 13)) << 16) & 0xff0000) |
+ (((*(iv + 14)) << 8) & 0xff00) |
+ (*(iv + 15) & 0xff);
+ cntr_iv64 =
+ (((unsigned long long)cntr_iv3 &
+ (unsigned long long)0xFFFFFFFFULL) +
+ (unsigned long long)num_blk) %
+ (unsigned long long)(0x100000000ULL);
+
+ cntr_iv3 = (u32)(cntr_iv64 & 0xFFFFFFFF);
+ *(iv + 15) = (char)(*b);
+ *(iv + 14) = (char)(*(b + 1));
+ *(iv + 13) = (char)(*(b + 2));
+ *(iv + 12) = (char)(*(b + 3));
}
} else {
memcpy(iv,
@@ -1456,10 +1471,11 @@
0, &pcl_info->encr_xts_key);
for (i = 1; i < xts_key_reg; i++)
qce_add_cmd_element(pdev, &ce_vaddr,
- (CRYPTO_ENCR_KEY0_REG + i * sizeof(uint32_t)),
- 0, NULL);
+ (CRYPTO_ENCR_XTS_KEY0_REG +
+ i * sizeof(uint32_t)), 0, NULL);
qce_add_cmd_element(pdev, &ce_vaddr,
- CRYPTO_ENCR_XTS_DU_SIZE_REG, 0, NULL);
+ CRYPTO_ENCR_XTS_DU_SIZE_REG, 0,
+ &pcl_info->encr_xts_du_size);
}
if (iv_reg) {
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CNTR0_IV0_REG, 0,
@@ -1624,13 +1640,6 @@
0, &pcl_info->auth_seg_size);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
0, &pcl_info->auth_seg_size);
- } else {
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_SIZE_REG,
- 0, &pcl_info->auth_seg_size);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, &pcl_info->auth_seg_size);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_START_REG,
- 0, &pcl_info->auth_seg_size);
}
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
(crypto_cfg | CRYPTO_LITTLE_ENDIAN_MASK),
diff --git a/drivers/crypto/msm/qcryptohw_50.h b/drivers/crypto/msm/qcryptohw_50.h
index 1c904ed..d77311d 100644
--- a/drivers/crypto/msm/qcryptohw_50.h
+++ b/drivers/crypto/msm/qcryptohw_50.h
@@ -144,7 +144,7 @@
#define CRYPTO_ENCR_CCM_INT_CNTR2_REG 0x1A228
#define CRYPTO_ENCR_CCM_INT_CNTR3_REG 0x1A22C
-#define CRYPTO_ENCR_XTS_DU_SIZE_REG 0xA1230
+#define CRYPTO_ENCR_XTS_DU_SIZE_REG 0x1A230
#define CRYPTO_AUTH_SEG_CFG_REG 0x1A300
#define CRYPTO_AUTH_SEG_SIZE_REG 0x1A304
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 7fe47ee..20f84d6 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -24,6 +24,7 @@
#include <linux/sched.h>
#include <linux/rwsem.h>
#include <linux/uaccess.h>
+#include <linux/memblock.h>
#include <mach/ion.h>
#include <mach/msm_memtypes.h>
#include "../ion_priv.h"
@@ -88,6 +89,16 @@
.name = ION_AUDIO_HEAP_NAME,
},
{
+ .id = ION_PIL1_HEAP_ID,
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .name = ION_PIL1_HEAP_NAME,
+ },
+ {
+ .id = ION_PIL2_HEAP_ID,
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .name = ION_PIL2_HEAP_NAME,
+ },
+ {
.id = ION_CP_WB_HEAP_ID,
.type = ION_HEAP_TYPE_CP,
.name = ION_WB_HEAP_NAME,
@@ -458,6 +469,7 @@
{
unsigned int val;
int ret = 0;
+ u32 out_values[2];
const char *memory_name_prop;
ret = of_property_read_u32(node, "qcom,memory-reservation-size", &val);
@@ -481,12 +493,29 @@
ret = -EINVAL;
}
} else {
- ret = 0;
+ ret = of_property_read_u32_array(node, "qcom,memory-fixed",
+ out_values, 2);
+ if (!ret)
+ heap->size = out_values[1];
+ else
+ ret = 0;
}
out:
return ret;
}
+static void msm_ion_get_heap_base(struct device_node *node,
+ struct ion_platform_heap *heap)
+{
+ u32 out_values[2];
+ int ret = 0;
+
+ ret = of_property_read_u32_array(node, "qcom,memory-fixed",
+ out_values, 2);
+ if (!ret)
+ heap->base = out_values[0];
+ return;
+}
static void msm_ion_get_heap_adjacent(struct device_node *node,
struct ion_platform_heap *heap)
@@ -560,6 +589,7 @@
if (ret)
goto free_heaps;
+ msm_ion_get_heap_base(node, &pdata->heaps[idx]);
msm_ion_get_heap_align(node, &pdata->heaps[idx]);
ret = msm_ion_get_heap_size(node, &pdata->heaps[idx]);
@@ -734,6 +764,19 @@
if (pdata_needs_to_be_freed)
free_pdata(pdata);
+ /* Check if each heap has been removed from the memblock */
+ for (i = 0; i < num_heaps; i++) {
+ struct ion_platform_heap *heap_data = &pdata->heaps[i];
+ if (!heap_data->base)
+ continue;
+ err = memblock_overlaps_memory(heap_data->base,
+ heap_data->size);
+ if (err) {
+ panic("ION heap %s not removed from memblock\n",
+ heap_data->name);
+ }
+ }
+
check_for_heap_overlap(pdata->heaps, num_heaps);
platform_set_drvdata(pdev, idev);
return 0;
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 18784ac..67cb34a 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1840,7 +1840,7 @@
goto err;
/* now, wait for the GPU to finish its operations */
- wait_time = jiffies + ADRENO_IDLE_TIMEOUT;
+ wait_time = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
wait_time_part = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART);
while (time_before(jiffies, wait_time)) {
@@ -1869,18 +1869,46 @@
KGSL_DRV_ERR(device, "spun too long waiting for RB to idle\n");
if (KGSL_STATE_DUMP_AND_RECOVER != device->state &&
!adreno_dump_and_recover(device)) {
- wait_time = jiffies + ADRENO_IDLE_TIMEOUT;
+ wait_time = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
goto retry;
}
return -ETIMEDOUT;
}
+/**
+ * is_adreno_rbbm_status_idle - Check if GPU core is idle by probing
+ * rbbm_status register
+ * @device - Pointer to the GPU device whose idle status is to be
+ * checked
+ * @returns - Returns whether the core is idle (based on rbbm_status)
+ * false if the core is active, true if the core is idle
+ */
+static bool is_adreno_rbbm_status_idle(struct kgsl_device *device)
+{
+ unsigned int reg_rbbm_status;
+ bool status = false;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+ /* Is the core idle? */
+ adreno_regread(device,
+ adreno_dev->gpudev->reg_rbbm_status,
+ ®_rbbm_status);
+
+ if (adreno_is_a2xx(adreno_dev)) {
+ if (reg_rbbm_status == 0x110)
+ status = true;
+ } else {
+ if (!(reg_rbbm_status & 0x80000000))
+ status = true;
+ }
+ return status;
+}
+
static unsigned int adreno_isidle(struct kgsl_device *device)
{
int status = false;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
- unsigned int rbbm_status;
WARN_ON(device->state == KGSL_STATE_INIT);
/* If the device isn't active, don't force it on. */
@@ -1889,17 +1917,7 @@
GSL_RB_GET_READPTR(rb, &rb->rptr);
if (!device->active_cnt && (rb->rptr == rb->wptr)) {
/* Is the core idle? */
- adreno_regread(device,
- adreno_dev->gpudev->reg_rbbm_status,
- &rbbm_status);
-
- if (adreno_is_a2xx(adreno_dev)) {
- if (rbbm_status == 0x110)
- status = true;
- } else {
- if (!(rbbm_status & 0x80000000))
- status = true;
- }
+ status = is_adreno_rbbm_status_idle(device);
}
} else {
status = true;
@@ -2142,7 +2160,7 @@
if (!adreno_dev->fast_hang_detect)
return 0;
- if (device->ftbl->isidle(device))
+ if (is_adreno_rbbm_status_idle(device))
return 0;
for (i = 0; i < hang_detect_regs_count; i++) {
diff --git a/drivers/gpu/msm/adreno_a2xx_snapshot.c b/drivers/gpu/msm/adreno_a2xx_snapshot.c
index 282440c..ce74c1b 100644
--- a/drivers/gpu/msm/adreno_a2xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a2xx_snapshot.c
@@ -224,6 +224,31 @@
return DEBUG_SECTION_SZ(MIUDEBUG_COUNT);
}
+/* Snapshot the istore memory */
+static int a2xx_snapshot_istore(struct kgsl_device *device, void *snapshot,
+ int remain, void *priv)
+{
+ struct kgsl_snapshot_istore *header = snapshot;
+ unsigned int *data = snapshot + sizeof(*header);
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ int count, i;
+
+ count = adreno_dev->istore_size * adreno_dev->instruction_size;
+
+ if (remain < (count * 4) + sizeof(*header)) {
+ KGSL_DRV_ERR(device,
+ "snapshot: Not enough memory for the istore section");
+ return 0;
+ }
+
+ header->count = adreno_dev->istore_size;
+
+ for (i = 0; i < count; i++)
+ kgsl_regread(device, ADRENO_ISTORE_START + i, &data[i]);
+
+ return (count * 4) + sizeof(*header);
+}
+
/* A2XX GPU snapshot function - this is where all of the A2XX specific
* bits and pieces are grabbed into the snapshot memory
*/
@@ -338,6 +363,18 @@
}
}
+ /*
+ * Only dump the istore on a hang - reading it on a running system
+ * has a non zero chance of hanging the GPU.
+ */
+
+ if (adreno_is_a2xx(adreno_dev) && hang) {
+ snapshot = kgsl_snapshot_add_section(device,
+ KGSL_SNAPSHOT_SECTION_ISTORE, snapshot, remain,
+ a2xx_snapshot_istore, NULL);
+ }
+
+
/* Reset the clock gating */
adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, pmoverride);
diff --git a/drivers/gpu/msm/adreno_a3xx_snapshot.c b/drivers/gpu/msm/adreno_a3xx_snapshot.c
index a410445..e4f5733 100644
--- a/drivers/gpu/msm/adreno_a3xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a3xx_snapshot.c
@@ -220,30 +220,46 @@
return DEBUG_SECTION_SZ(size);
}
-#define DEBUGFS_BLOCK_SIZE 0x40
+struct debugbus_block {
+ unsigned int block_id;
+ unsigned int dwords;
+};
static int a3xx_snapshot_debugbus_block(struct kgsl_device *device,
void *snapshot, int remain, void *priv)
{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
struct kgsl_snapshot_debugbus *header = snapshot;
- unsigned int id = (unsigned int) priv;
+ struct debugbus_block *block = priv;
unsigned int val;
int i;
unsigned int *data = snapshot + sizeof(*header);
- int size =
- (DEBUGFS_BLOCK_SIZE * sizeof(unsigned int)) + sizeof(*header);
+ unsigned int dwords;
+ int size;
+
+ /*
+ * For A305 and A320 all debug bus regions are the same size (0x40). For
+ * A330, they can be different sizes - most are still 0x40, but some
+ * like CP are larger
+ */
+
+ dwords = adreno_is_a330(adreno_dev) ?
+ block->dwords : 0x40;
+
+ size = (dwords * sizeof(unsigned int)) + sizeof(*header);
if (remain < size) {
SNAPSHOT_ERR_NOMEM(device, "DEBUGBUS");
return 0;
}
- val = (id << 8) | (1 << 16);
+ val = (block->block_id << 8) | (1 << 16);
- header->id = id;
- header->count = DEBUGFS_BLOCK_SIZE;
+ header->id = block->block_id;
+ header->count = dwords;
- for (i = 0; i < DEBUGFS_BLOCK_SIZE; i++) {
+ for (i = 0; i < dwords; i++) {
adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_CTL, val | i);
adreno_regread(device, A3XX_RBBM_DEBUG_BUS_DATA_STATUS,
&data[i]);
@@ -252,34 +268,34 @@
return size;
}
-static unsigned int debugbus_blocks[] = {
- RBBM_BLOCK_ID_CP,
- RBBM_BLOCK_ID_RBBM,
- RBBM_BLOCK_ID_VBIF,
- RBBM_BLOCK_ID_HLSQ,
- RBBM_BLOCK_ID_UCHE,
- RBBM_BLOCK_ID_PC,
- RBBM_BLOCK_ID_VFD,
- RBBM_BLOCK_ID_VPC,
- RBBM_BLOCK_ID_TSE,
- RBBM_BLOCK_ID_RAS,
- RBBM_BLOCK_ID_VSC,
- RBBM_BLOCK_ID_SP_0,
- RBBM_BLOCK_ID_SP_1,
- RBBM_BLOCK_ID_SP_2,
- RBBM_BLOCK_ID_SP_3,
- RBBM_BLOCK_ID_TPL1_0,
- RBBM_BLOCK_ID_TPL1_1,
- RBBM_BLOCK_ID_TPL1_2,
- RBBM_BLOCK_ID_TPL1_3,
- RBBM_BLOCK_ID_RB_0,
- RBBM_BLOCK_ID_RB_1,
- RBBM_BLOCK_ID_RB_2,
- RBBM_BLOCK_ID_RB_3,
- RBBM_BLOCK_ID_MARB_0,
- RBBM_BLOCK_ID_MARB_1,
- RBBM_BLOCK_ID_MARB_2,
- RBBM_BLOCK_ID_MARB_3,
+static struct debugbus_block debugbus_blocks[] = {
+ { RBBM_BLOCK_ID_CP, 0x52, },
+ { RBBM_BLOCK_ID_RBBM, 0x40, },
+ { RBBM_BLOCK_ID_VBIF, 0x40, },
+ { RBBM_BLOCK_ID_HLSQ, 0x40, },
+ { RBBM_BLOCK_ID_UCHE, 0x40, },
+ { RBBM_BLOCK_ID_PC, 0x40, },
+ { RBBM_BLOCK_ID_VFD, 0x40, },
+ { RBBM_BLOCK_ID_VPC, 0x40, },
+ { RBBM_BLOCK_ID_TSE, 0x40, },
+ { RBBM_BLOCK_ID_RAS, 0x40, },
+ { RBBM_BLOCK_ID_VSC, 0x40, },
+ { RBBM_BLOCK_ID_SP_0, 0x40, },
+ { RBBM_BLOCK_ID_SP_1, 0x40, },
+ { RBBM_BLOCK_ID_SP_2, 0x40, },
+ { RBBM_BLOCK_ID_SP_3, 0x40, },
+ { RBBM_BLOCK_ID_TPL1_0, 0x40, },
+ { RBBM_BLOCK_ID_TPL1_1, 0x40, },
+ { RBBM_BLOCK_ID_TPL1_2, 0x40, },
+ { RBBM_BLOCK_ID_TPL1_3, 0x40, },
+ { RBBM_BLOCK_ID_RB_0, 0x40, },
+ { RBBM_BLOCK_ID_RB_1, 0x40, },
+ { RBBM_BLOCK_ID_RB_2, 0x40, },
+ { RBBM_BLOCK_ID_RB_3, 0x40, },
+ { RBBM_BLOCK_ID_MARB_0, 0x40, },
+ { RBBM_BLOCK_ID_MARB_1, 0x40, },
+ { RBBM_BLOCK_ID_MARB_2, 0x40, },
+ { RBBM_BLOCK_ID_MARB_3, 0x40, },
};
static void *a3xx_snapshot_debugbus(struct kgsl_device *device,
@@ -291,7 +307,7 @@
snapshot = kgsl_snapshot_add_section(device,
KGSL_SNAPSHOT_SECTION_DEBUGBUS, snapshot, remain,
a3xx_snapshot_debugbus_block,
- (void *) debugbus_blocks[i]);
+ (void *) &debugbus_blocks[i]);
}
return snapshot;
@@ -307,6 +323,7 @@
struct kgsl_device *device = &adreno_dev->dev;
struct kgsl_snapshot_registers_list list;
struct kgsl_snapshot_registers regs[2];
+ int size;
regs[0].regs = (unsigned int *) a3xx_registers;
regs[0].count = a3xx_registers_count;
@@ -326,10 +343,14 @@
KGSL_SNAPSHOT_SECTION_REGS, snapshot, remain,
kgsl_snapshot_dump_regs, &list);
- /* CP_STATE_DEBUG indexed registers */
+ /*
+ * CP_STATE_DEBUG indexed registers - 20 on 305 and 320 and 46 on A330
+ */
+ size = adreno_is_a330(adreno_dev) ? 0x2E : 0x14;
+
snapshot = kgsl_snapshot_indexed_registers(device, snapshot,
remain, REG_CP_STATE_DEBUG_INDEX,
- REG_CP_STATE_DEBUG_DATA, 0x0, 0x14);
+ REG_CP_STATE_DEBUG_DATA, 0x0, size);
/* CP_ME indexed registers */
snapshot = kgsl_snapshot_indexed_registers(device, snapshot,
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index 93be980..696073f 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -510,10 +510,28 @@
break;
if (pkt_is_type3(src[i])) {
- if (adreno_cmd_is_ib(src[i]))
- ib_add_gpu_object(device, ptbase,
- src[i + 1], src[i + 2]);
- else
+ if (adreno_cmd_is_ib(src[i])) {
+ unsigned int gpuaddr = src[i + 1];
+ unsigned int size = src[i + 2];
+ unsigned int ibbase;
+
+ /* Address of the last processed IB2 */
+ kgsl_regread(device, REG_CP_IB2_BASE, &ibbase);
+
+ /*
+ * If this is the last IB2 that was executed,
+ * then push it to make sure it goes into the
+ * static space
+ */
+
+ if (ibbase == gpuaddr)
+ push_object(device,
+ SNAPSHOT_OBJ_TYPE_IB, ptbase,
+ gpuaddr, size);
+ else
+ ib_add_gpu_object(device, ptbase,
+ gpuaddr, size);
+ } else
ib_parse_type3(device, &src[i], ptbase);
} else if (pkt_is_type0(src[i])) {
ib_parse_type0(device, &src[i], ptbase);
@@ -529,31 +547,6 @@
snapshot_frozen_objsize += ret;
}
-/* Snapshot the istore memory */
-static int snapshot_istore(struct kgsl_device *device, void *snapshot,
- int remain, void *priv)
-{
- struct kgsl_snapshot_istore *header = snapshot;
- unsigned int *data = snapshot + sizeof(*header);
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- int count, i;
-
- count = adreno_dev->istore_size * adreno_dev->instruction_size;
-
- if (remain < (count * 4) + sizeof(*header)) {
- KGSL_DRV_ERR(device,
- "snapshot: Not enough memory for the istore section");
- return 0;
- }
-
- header->count = adreno_dev->istore_size;
-
- for (i = 0; i < count; i++)
- kgsl_regread(device, ADRENO_ISTORE_START + i, &data[i]);
-
- return (count * 4) + sizeof(*header);
-}
-
/* Snapshot the ringbuffer memory */
static int snapshot_rb(struct kgsl_device *device, void *snapshot,
int remain, void *priv)
@@ -870,17 +863,6 @@
for (i = 0; i < objbufptr; i++)
snapshot = dump_object(device, i, snapshot, remain);
- /*
- * Only dump the istore on a hang - reading it on a running system
- * has a non 0 chance of hanging the GPU
- */
-
- if (hang) {
- snapshot = kgsl_snapshot_add_section(device,
- KGSL_SNAPSHOT_SECTION_ISTORE, snapshot, remain,
- snapshot_istore, NULL);
- }
-
/* Add GPU specific sections - registers mainly, but other stuff too */
if (adreno_dev->gpudev->snapshot)
snapshot = adreno_dev->gpudev->snapshot(adreno_dev, snapshot,
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 7194e47..b8adbe67 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -333,14 +333,19 @@
context = kzalloc(sizeof(*context), GFP_KERNEL);
- if (context == NULL)
- return NULL;
+ if (context == NULL) {
+ KGSL_DRV_INFO(dev_priv->device, "kzalloc(%d) failed\n",
+ sizeof(*context));
+ return ERR_PTR(-ENOMEM);
+ }
while (1) {
if (idr_pre_get(&dev_priv->device->context_idr,
GFP_KERNEL) == 0) {
- kfree(context);
- return NULL;
+ KGSL_DRV_INFO(dev_priv->device,
+ "idr_pre_get: ENOMEM\n");
+ ret = -ENOMEM;
+ goto func_end;
}
ret = idr_get_new_above(&dev_priv->device->context_idr,
@@ -350,10 +355,8 @@
break;
}
- if (ret) {
- kfree(context);
- return NULL;
- }
+ if (ret)
+ goto func_end;
/* MAX - 1, there is one memdesc in memstore for device info */
if (id >= KGSL_MEMSTORE_MAX) {
@@ -361,18 +364,24 @@
"ctxts due to memstore limitation\n",
KGSL_MEMSTORE_MAX);
idr_remove(&dev_priv->device->context_idr, id);
- kfree(context);
- return NULL;
+ ret = -ENOSPC;
+ goto func_end;
}
kref_init(&context->refcount);
context->id = id;
context->dev_priv = dev_priv;
- if (kgsl_sync_timeline_create(context)) {
+ ret = kgsl_sync_timeline_create(context);
+ if (ret) {
idr_remove(&dev_priv->device->context_idr, id);
+ goto func_end;
+ }
+
+func_end:
+ if (ret) {
kfree(context);
- return NULL;
+ return ERR_PTR(ret);
}
return context;
@@ -1283,8 +1292,8 @@
context = kgsl_create_context(dev_priv);
- if (context == NULL) {
- result = -ENOMEM;
+ if (IS_ERR(context)) {
+ result = PTR_ERR(context);
goto done;
}
@@ -1298,7 +1307,7 @@
trace_kgsl_context_create(dev_priv->device, context, param->flags);
param->drawctxt_id = context->id;
done:
- if (result && context)
+ if (result && !IS_ERR(context))
kgsl_context_detach(context);
return result;
@@ -1710,6 +1719,8 @@
else
memtype = param->memtype;
+ entry->memdesc.flags = param->flags;
+
switch (memtype) {
case KGSL_USER_MEM_TYPE_PMEM:
if (param->fd == 0 || param->len == 0)
@@ -1768,12 +1779,10 @@
if (result)
goto error;
- entry->memdesc.priv |= param->flags & KGSL_MEMTYPE_MASK;
-
if (entry->memdesc.size >= SZ_1M)
- entry->memdesc.priv |= ilog2(SZ_1M) << KGSL_MEMALIGN_SHIFT;
+ kgsl_memdesc_set_align(&entry->memdesc, ilog2(SZ_1M));
else if (entry->memdesc.size >= SZ_64K)
- entry->memdesc.priv |= ilog2(SZ_64K) << KGSL_MEMALIGN_SHIFT;
+ kgsl_memdesc_set_align(&entry->memdesc, ilog2(SZ_64));
result = kgsl_mmu_map(private->pagetable,
&entry->memdesc,
@@ -2538,6 +2547,9 @@
KGSL_LOG_DUMP(device, "POWER: INTERVAL TIMEOUT = %08X ",
pwr->interval_timeout);
+ KGSL_LOG_DUMP(device, "POWER: NAP ALLOWED = %d | START_STOP_SLEEP_WAKE = %d\n",
+ pwr->nap_allowed, pwr->strtstp_sleepwake);
+
KGSL_LOG_DUMP(device, "GRP_CLK = %lu ",
kgsl_get_clkrate(pwr->grp_clks[0]));
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 56950a6..17a5b67 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -124,7 +124,10 @@
int (*map_kernel_mem)(struct kgsl_memdesc *);
};
+/* Internal definitions for memdesc->priv */
#define KGSL_MEMDESC_GUARD_PAGE BIT(0)
+/* Set if the memdesc is mapped into all pagetables */
+#define KGSL_MEMDESC_GLOBAL BIT(1)
/* shared memory allocation */
struct kgsl_memdesc {
@@ -134,12 +137,12 @@
unsigned int gpuaddr;
unsigned int physaddr;
unsigned int size;
- unsigned int priv;
+ unsigned int priv; /* Internal flags and settings */
struct scatterlist *sg;
unsigned int sglen; /* Active entries in the sglist */
unsigned int sglen_alloc; /* Allocated entries in the sglist */
struct kgsl_memdesc_ops *ops;
- int flags;
+ unsigned int flags; /* Flags set from userspace */
};
/* List of different memory entry types */
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index b49c260..52097dc 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -163,6 +163,16 @@
return "unknown";
}
+static char get_alignflag(const struct kgsl_memdesc *m)
+{
+ int align = kgsl_memdesc_get_align(m);
+ if (align >= ilog2(SZ_1M))
+ return 'L';
+ else if (align >= ilog2(SZ_64K))
+ return 'l';
+ return '-';
+}
+
static int process_mem_print(struct seq_file *s, void *unused)
{
struct kgsl_mem_entry *entry;
@@ -170,7 +180,6 @@
struct kgsl_process_private *private = s->private;
char flags[4];
char usage[16];
- unsigned int align;
spin_lock(&private->mem_lock);
seq_printf(s, "%8s %8s %5s %10s %16s %5s\n",
@@ -181,20 +190,12 @@
entry = rb_entry(node, struct kgsl_mem_entry, node);
m = &entry->memdesc;
- flags[0] = m->priv & KGSL_MEMFLAGS_GLOBAL ? 'g' : '-';
- flags[1] = m->priv & KGSL_MEMFLAGS_GPUREADONLY ? 'r' : '-';
-
- align = (m->priv & KGSL_MEMALIGN_MASK) >> KGSL_MEMALIGN_SHIFT;
- if (align >= ilog2(SZ_1M))
- flags[2] = 'L';
- else if (align >= ilog2(SZ_64K))
- flags[2] = 'l';
- else
- flags[2] = '-';
-
+ flags[0] = m->priv & KGSL_MEMDESC_GLOBAL ? 'g' : '-';
+ flags[1] = m->flags & KGSL_MEMFLAGS_GPUREADONLY ? 'r' : '-';
+ flags[2] = get_alignflag(m);
flags[3] = '\0';
- kgsl_get_memory_usage(usage, sizeof(usage), m->priv);
+ kgsl_get_memory_usage(usage, sizeof(usage), m->flags);
seq_printf(s, "%08x %8d %5s %10s %16s %5d\n",
m->gpuaddr, m->size, flags,
diff --git a/drivers/gpu/msm/kgsl_drm.c b/drivers/gpu/msm/kgsl_drm.c
index 870a7d7..2003098 100644
--- a/drivers/gpu/msm/kgsl_drm.c
+++ b/drivers/gpu/msm/kgsl_drm.c
@@ -237,14 +237,16 @@
}
}
+ /* Set the flags for the memdesc (probably 0, unless it is cached) */
+ priv->memdesc.priv = 0;
+
if (TYPE_IS_PMEM(priv->type)) {
if (priv->type == DRM_KGSL_GEM_TYPE_EBI ||
priv->type & DRM_KGSL_GEM_PMEM_EBI) {
result = kgsl_sharedmem_ebimem_user(
&priv->memdesc,
priv->pagetable,
- obj->size * priv->bufcount,
- 0);
+ obj->size * priv->bufcount);
if (result) {
DRM_ERROR(
"Unable to allocate PMEM memory\n");
@@ -262,7 +264,7 @@
result = kgsl_sharedmem_page_alloc_user(&priv->memdesc,
priv->pagetable,
- obj->size * priv->bufcount, 0);
+ obj->size * priv->bufcount);
if (result != 0) {
DRM_ERROR(
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 62108f2..07ea48e 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -792,13 +792,13 @@
if (msm_soc_version_supports_iommu_v1()) {
for (i = 0; i < iommu->unit_count; i++) {
iommu->iommu_units[i].reg_map.priv |=
- KGSL_MEMFLAGS_GLOBAL;
+ KGSL_MEMDESC_GLOBAL;
status = kgsl_mmu_map(pagetable,
&(iommu->iommu_units[i].reg_map),
GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
if (status) {
iommu->iommu_units[i].reg_map.priv &=
- ~KGSL_MEMFLAGS_GLOBAL;
+ ~KGSL_MEMDESC_GLOBAL;
goto err;
}
}
@@ -808,7 +808,7 @@
for (i--; i >= 0; i--) {
kgsl_mmu_unmap(pagetable,
&(iommu->iommu_units[i].reg_map));
- iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMFLAGS_GLOBAL;
+ iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMDESC_GLOBAL;
}
if (mmu->priv_bank_table) {
kgsl_mmu_putpagetable(mmu->priv_bank_table);
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index dbb88ee..68cd167 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -593,7 +593,7 @@
_get_pool(struct kgsl_pagetable *pagetable, unsigned int flags)
{
if (pagetable->kgsl_pool &&
- (KGSL_MEMFLAGS_GLOBAL & flags))
+ (KGSL_MEMDESC_GLOBAL & flags))
return pagetable->kgsl_pool;
return pagetable->pool;
}
@@ -637,10 +637,9 @@
* the address space is so small.
*/
if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype() &&
- (memdesc->priv & KGSL_MEMALIGN_MASK)) {
- page_align = (memdesc->priv & KGSL_MEMALIGN_MASK)
- >> KGSL_MEMALIGN_SHIFT;
- }
+ kgsl_memdesc_get_align(memdesc) > 0)
+ page_align = kgsl_memdesc_get_align(memdesc);
+
memdesc->gpuaddr = gen_pool_alloc_aligned(pool, size, page_align);
if (memdesc->gpuaddr == 0) {
KGSL_CORE_ERR("gen_pool_alloc(%d) failed from pool: %s\n",
@@ -719,7 +718,7 @@
* Don't clear the gpuaddr on global mappings because they
* may be in use by other pagetables
*/
- if (!(memdesc->priv & KGSL_MEMFLAGS_GLOBAL))
+ if (!(memdesc->priv & KGSL_MEMDESC_GLOBAL))
memdesc->gpuaddr = 0;
return 0;
}
@@ -740,8 +739,7 @@
return 0;
gpuaddr = memdesc->gpuaddr;
- memdesc->priv |= KGSL_MEMFLAGS_GLOBAL
- | (KGSL_MEMTYPE_KERNEL << KGSL_MEMTYPE_SHIFT);
+ memdesc->priv |= KGSL_MEMDESC_GLOBAL;
result = kgsl_mmu_map(pagetable, memdesc, protflags);
if (result)
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 739dcb5..422bd55 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -23,6 +23,7 @@
#include "kgsl_pwrscale.h"
#include "kgsl_device.h"
#include "kgsl_trace.h"
+#include "kgsl_sharedmem.h"
#define KGSL_PWRFLAGS_POWER_ON 0
#define KGSL_PWRFLAGS_CLK_ON 1
@@ -951,6 +952,11 @@
void kgsl_pwrctrl_wake(struct kgsl_device *device)
{
int status;
+ unsigned int context_id;
+ unsigned int state = device->state;
+ unsigned int ts_processed = 0xdeaddead;
+ struct kgsl_context *context;
+
kgsl_pwrctrl_request_state(device, KGSL_STATE_ACTIVE);
switch (device->state) {
case KGSL_STATE_SLUMBER:
@@ -964,6 +970,17 @@
case KGSL_STATE_SLEEP:
kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
kgsl_pwrscale_wake(device);
+ kgsl_sharedmem_readl(&device->memstore,
+ (unsigned int *) &context_id,
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ current_context));
+ context = idr_find(&device->context_idr, context_id);
+ if (context)
+ ts_processed = kgsl_readtimestamp(device, context,
+ KGSL_TIMESTAMP_RETIRED);
+ KGSL_PWR_INFO(device, "Wake from %s state. CTXT: %d RTRD TS: %08X\n",
+ kgsl_pwrstate_to_str(state),
+ context ? context->id : -1, ts_processed);
/* fall through */
case KGSL_STATE_NAP:
/* Turn on the core clocks */
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index 53dc468..a70647a 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -367,7 +367,7 @@
int sglen = memdesc->sglen;
/* Don't free the guard page if it was used */
- if (memdesc->flags & KGSL_MEMDESC_GUARD_PAGE)
+ if (memdesc->priv & KGSL_MEMDESC_GUARD_PAGE)
sglen--;
kgsl_driver.stats.page_alloc -= memdesc->size;
@@ -405,7 +405,7 @@
int i, count = 0;
/* Don't map the guard page if it exists */
- if (memdesc->flags & KGSL_MEMDESC_GUARD_PAGE)
+ if (memdesc->priv & KGSL_MEMDESC_GUARD_PAGE)
sglen--;
/* create a list of pages to call vmap */
@@ -534,7 +534,7 @@
static int
_kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc,
struct kgsl_pagetable *pagetable,
- size_t size, unsigned int flags, unsigned int protflags)
+ size_t size, unsigned int protflags)
{
int pcount = 0, order, ret = 0;
int j, len, page_size, sglen_alloc, sglen = 0;
@@ -562,10 +562,12 @@
if (size >= ((si.freeram << PAGE_SHIFT) - SZ_32M))
return -ENOMEM;
- align = (flags & KGSL_MEMALIGN_MASK) >> KGSL_MEMALIGN_SHIFT;
+ align = (memdesc->flags & KGSL_MEMALIGN_MASK) >> KGSL_MEMALIGN_SHIFT;
page_size = (align >= ilog2(SZ_64K) && size >= SZ_64K)
? SZ_64K : PAGE_SIZE;
+ /* update align flags for what we actually use */
+ kgsl_memdesc_set_align(memdesc, ilog2(page_size));
/*
* There needs to be enough room in the sg structure to be able to
@@ -584,7 +586,6 @@
memdesc->size = size;
memdesc->pagetable = pagetable;
- memdesc->priv |= (flags & KGSL_MEMALIGN_MASK);
memdesc->ops = &kgsl_page_alloc_ops;
memdesc->sg = kgsl_sg_alloc(sglen_alloc);
@@ -664,7 +665,7 @@
if (kgsl_guard_page != NULL) {
sg_set_page(&memdesc->sg[sglen++], kgsl_guard_page,
PAGE_SIZE, 0);
- memdesc->flags |= KGSL_MEMDESC_GUARD_PAGE;
+ memdesc->priv |= KGSL_MEMDESC_GUARD_PAGE;
}
}
@@ -741,7 +742,7 @@
size = ALIGN(size, PAGE_SIZE * 2);
ret = _kgsl_sharedmem_page_alloc(memdesc, pagetable, size,
- 0, GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+ GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
if (!ret)
ret = kgsl_page_alloc_map_kernel(memdesc);
if (ret)
@@ -753,7 +754,7 @@
int
kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc,
struct kgsl_pagetable *pagetable,
- size_t size, int flags)
+ size_t size)
{
unsigned int protflags;
@@ -761,11 +762,11 @@
return -EINVAL;
protflags = GSL_PT_PAGE_RV;
- if (!(flags & KGSL_MEMFLAGS_GPUREADONLY))
+ if (!(memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY))
protflags |= GSL_PT_PAGE_WV;
return _kgsl_sharedmem_page_alloc(memdesc, pagetable, size,
- flags, protflags);
+ protflags);
}
EXPORT_SYMBOL(kgsl_sharedmem_page_alloc_user);
@@ -862,7 +863,7 @@
int
kgsl_sharedmem_ebimem_user(struct kgsl_memdesc *memdesc,
struct kgsl_pagetable *pagetable,
- size_t size, int flags)
+ size_t size)
{
size = ALIGN(size, PAGE_SIZE);
return _kgsl_sharedmem_ebimem(memdesc, pagetable, size);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 5a6c4c2..92a6f27 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -20,6 +20,8 @@
#include <linux/slab.h>
#include <linux/kmemleak.h>
+#include "kgsl_log.h"
+
struct kgsl_device;
struct kgsl_process_private;
@@ -27,9 +29,6 @@
#define KGSL_CACHE_OP_FLUSH 0x02
#define KGSL_CACHE_OP_CLEAN 0x03
-/** Set if the memdesc is mapped into all pagetables */
-#define KGSL_MEMFLAGS_GLOBAL 0x00000002
-
extern struct kgsl_memdesc_ops kgsl_page_alloc_ops;
int kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc,
@@ -37,13 +36,13 @@
int kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc,
struct kgsl_pagetable *pagetable,
- size_t size, int flags);
+ size_t size);
int kgsl_sharedmem_alloc_coherent(struct kgsl_memdesc *memdesc, size_t size);
int kgsl_sharedmem_ebimem_user(struct kgsl_memdesc *memdesc,
struct kgsl_pagetable *pagetable,
- size_t size, int flags);
+ size_t size);
int kgsl_sharedmem_ebimem(struct kgsl_memdesc *memdesc,
struct kgsl_pagetable *pagetable,
@@ -71,6 +70,36 @@
int kgsl_sharedmem_init_sysfs(void);
void kgsl_sharedmem_uninit_sysfs(void);
+/*
+ * kgsl_memdesc_get_align - Get alignment flags from a memdesc
+ * @memdesc - the memdesc
+ *
+ * Returns the alignment requested, as power of 2 exponent.
+ */
+static inline int
+kgsl_memdesc_get_align(const struct kgsl_memdesc *memdesc)
+{
+ return (memdesc->flags & KGSL_MEMALIGN_MASK) >> KGSL_MEMALIGN_SHIFT;
+}
+
+/*
+ * kgsl_memdesc_set_align - Set alignment flags of a memdesc
+ * @memdesc - the memdesc
+ * @align - alignment requested, as a power of 2 exponent.
+ */
+static inline int
+kgsl_memdesc_set_align(struct kgsl_memdesc *memdesc, unsigned int align)
+{
+ if (align > 32) {
+ KGSL_CORE_ERR("Alignment too big, restricting to 2^32\n");
+ align = 32;
+ }
+
+ memdesc->flags &= ~KGSL_MEMALIGN_MASK;
+ memdesc->flags |= (align << KGSL_MEMALIGN_SHIFT) & KGSL_MEMALIGN_MASK;
+ return 0;
+}
+
static inline unsigned int kgsl_get_sg_pa(struct scatterlist *sg)
{
/*
@@ -134,7 +163,7 @@
{
if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_NONE)
return kgsl_sharedmem_ebimem(memdesc, pagetable, size);
- memdesc->priv |= (KGSL_MEMTYPE_KERNEL << KGSL_MEMTYPE_SHIFT);
+ memdesc->flags |= (KGSL_MEMTYPE_KERNEL << KGSL_MEMTYPE_SHIFT);
return kgsl_sharedmem_page_alloc(memdesc, pagetable, size);
}
@@ -144,15 +173,14 @@
size_t size, unsigned int flags)
{
int ret;
- unsigned int mask = (KGSL_MEMTYPE_MASK | KGSL_MEMFLAGS_GPUREADONLY);
+
+ memdesc->flags = flags;
+
if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_NONE)
- ret = kgsl_sharedmem_ebimem_user(memdesc, pagetable, size,
- flags);
+ ret = kgsl_sharedmem_ebimem_user(memdesc, pagetable, size);
else
- ret = kgsl_sharedmem_page_alloc_user(memdesc, pagetable, size,
- flags);
- if (ret == 0)
- memdesc->priv |= flags & mask;
+ ret = kgsl_sharedmem_page_alloc_user(memdesc, pagetable, size);
+
return ret;
}
@@ -162,6 +190,8 @@
int ret = kgsl_sharedmem_alloc_coherent(memdesc, size);
if (!ret && (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_NONE))
memdesc->gpuaddr = memdesc->physaddr;
+
+ memdesc->flags |= (KGSL_MEMTYPE_KERNEL << KGSL_MEMTYPE_SHIFT);
return ret;
}
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 81cb34f..0b247e5 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -324,7 +324,7 @@
__entry->size = mem_entry->memdesc.size;
__entry->tgid = mem_entry->priv->pid;
kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
- mem_entry->memdesc.priv);
+ mem_entry->memdesc.flags);
),
TP_printk(
@@ -356,7 +356,7 @@
__entry->type = mem_entry->memtype;
__entry->tgid = mem_entry->priv->pid;
kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
- mem_entry->memdesc.priv);
+ mem_entry->memdesc.flags);
),
TP_printk(
@@ -388,7 +388,7 @@
__entry->type = mem_entry->memtype;
__entry->tgid = mem_entry->priv->pid;
kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
- mem_entry->memdesc.priv);
+ mem_entry->memdesc.flags);
),
TP_printk(
@@ -421,7 +421,7 @@
__entry->gpuaddr = mem_entry->memdesc.gpuaddr;
__entry->size = mem_entry->memdesc.size;
kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
- mem_entry->memdesc.priv);
+ mem_entry->memdesc.flags);
__entry->drawctxt_id = id;
__entry->type = mem_entry->memtype;
__entry->curr_ts = curr_ts;
diff --git a/drivers/hwmon/epm_adc.c b/drivers/hwmon/epm_adc.c
index 368aac4..69a2f1c 100644
--- a/drivers/hwmon/epm_adc.c
+++ b/drivers/hwmon/epm_adc.c
@@ -1703,7 +1703,7 @@
}
static const struct of_device_id epm_adc_psoc_match_table[] = {
- { .compatible = "qcom,epm-adc",
+ { .compatible = "cy,epm-adc-cy8c5568lti-114",
},
{}
};
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index aa375d7..0a85b93 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -111,6 +111,13 @@
#define QPNP_DATA1 0x61
#define QPNP_CONV_TIMEOUT_ERR 2
+#define QPNP_IADC_SEC_ACCESS 0xD0
+#define QPNP_IADC_SEC_ACCESS_DATA 0xA5
+#define QPNP_IADC_MSB_OFFSET 0xF2
+#define QPNP_IADC_LSB_OFFSET 0xF3
+#define QPNP_IADC_NOMINAL_RSENSE 0xF4
+#define QPNP_IADC_ATE_GAIN_CALIB_OFFSET 0xF5
+
#define QPNP_IADC_ADC_CH_SEL_CTL 0x48
#define QPNP_IADC_ADC_CHX_SEL_SHIFT 3
@@ -127,15 +134,27 @@
#define QPNP_ADC_CONV_TIME_MIN 8000
#define QPNP_ADC_CONV_TIME_MAX 8200
-#define QPNP_ADC_GAIN_CALCULATION_UV 17857
-#define QPNP_IADC_RSENSE_MILLI_FACTOR 1000
+#define QPNP_ADC_GAIN_NV 17857
+#define QPNP_OFFSET_CALIBRATION_SHORT_CADC_LEADS_IDEAL 0
+#define QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR 10000000
+#define QPNP_IADC_NANO_VOLTS_FACTOR 1000000000
+#define QPNP_IADC_CALIB_SECONDS 300000
+#define QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT 15625
+#define QPNP_IADC_DIE_TEMP_CALIB_OFFSET 5000
+
+#define QPNP_RAW_CODE_16_BIT_MSB_MASK 0xff00
+#define QPNP_RAW_CODE_16_BIT_LSB_MASK 0xff
+#define QPNP_BIT_SHIFT_8 8
+#define QPNP_RSENSE_MSB_SIGN_CHECK 0x80
struct qpnp_iadc_drv {
- struct qpnp_adc_drv *adc;
- int32_t rsense;
- struct device *iadc_hwmon;
- bool iadc_init_calib;
- bool iadc_initialized;
+ struct qpnp_adc_drv *adc;
+ int32_t rsense;
+ struct device *iadc_hwmon;
+ bool iadc_init_calib;
+ bool iadc_initialized;
+ int64_t die_temp_calib_offset;
+ struct delayed_work iadc_work;
struct sensor_device_attribute sens_attr[0];
};
@@ -253,9 +272,10 @@
return 0;
}
-static int32_t qpnp_iadc_read_conversion_result(int32_t *data)
+static int32_t qpnp_iadc_read_conversion_result(uint16_t *data)
{
uint8_t rslt_lsb, rslt_msb;
+ uint16_t rslt;
int32_t rc;
rc = qpnp_iadc_read_reg(QPNP_IADC_DATA0, &rslt_lsb);
@@ -270,16 +290,18 @@
return rc;
}
- *data = (rslt_msb << 8) | rslt_lsb;
+ rslt = (rslt_msb << 8) | rslt_lsb;
+ *data = rslt;
rc = qpnp_iadc_enable(false);
if (rc)
return rc;
+
return 0;
}
static int32_t qpnp_iadc_configure(enum qpnp_iadc_channels channel,
- int32_t *result)
+ uint16_t *raw_code)
{
struct qpnp_iadc_drv *iadc = qpnp_iadc;
u8 qpnp_iadc_mode_reg = 0, qpnp_iadc_ch_sel_reg = 0;
@@ -346,7 +368,7 @@
wait_for_completion(&iadc->adc->adc_rslt_completion);
- rc = qpnp_iadc_read_conversion_result(result);
+ rc = qpnp_iadc_read_conversion_result(raw_code);
if (rc) {
pr_err("qpnp adc read adc failed with %d\n", rc);
return rc;
@@ -355,32 +377,109 @@
return 0;
}
-static int32_t qpnp_iadc_init_calib(void)
+static int32_t qpnp_convert_raw_offset_voltage(void)
{
struct qpnp_iadc_drv *iadc = qpnp_iadc;
- int32_t rc = 0, result;
+ uint32_t num = 0;
- rc = qpnp_iadc_configure(GAIN_CALIBRATION_25MV, &result);
+ num = iadc->adc->calib.offset_raw - iadc->adc->calib.offset_raw;
+
+ iadc->adc->calib.offset_uv = (num * QPNP_ADC_GAIN_NV)/
+ (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
+
+ num = iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw;
+
+ iadc->adc->calib.gain_uv = (num * QPNP_ADC_GAIN_NV)/
+ (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
+
+ return 0;
+}
+
+static int32_t qpnp_iadc_calibrate_for_trim(void)
+{
+ struct qpnp_iadc_drv *iadc = qpnp_iadc;
+ uint8_t rslt_lsb, rslt_msb;
+ int32_t rc = 0;
+ uint16_t raw_data;
+
+ rc = qpnp_iadc_configure(GAIN_CALIBRATION_17P857MV, &raw_data);
if (rc < 0) {
pr_err("qpnp adc result read failed with %d\n", rc);
goto fail;
}
- iadc->adc->calib.gain = result;
+ iadc->adc->calib.gain_raw = raw_data;
rc = qpnp_iadc_configure(OFFSET_CALIBRATION_SHORT_CADC_LEADS,
- &result);
+ &raw_data);
if (rc < 0) {
pr_err("qpnp adc result read failed with %d\n", rc);
goto fail;
}
- iadc->adc->calib.offset = result;
+ iadc->adc->calib.offset_raw = raw_data;
+ if (rc < 0) {
+ pr_err("qpnp adc offset/gain calculation failed\n");
+ goto fail;
+ }
+ rc = qpnp_convert_raw_offset_voltage();
+
+ rslt_msb = (raw_data & QPNP_RAW_CODE_16_BIT_MSB_MASK) >>
+ QPNP_BIT_SHIFT_8;
+ rslt_lsb = raw_data & QPNP_RAW_CODE_16_BIT_LSB_MASK;
+
+ rc = qpnp_iadc_write_reg(QPNP_IADC_SEC_ACCESS,
+ QPNP_IADC_SEC_ACCESS_DATA);
+ if (rc < 0) {
+ pr_err("qpnp iadc configure error for sec access\n");
+ goto fail;
+ }
+
+ rc = qpnp_iadc_write_reg(QPNP_IADC_MSB_OFFSET,
+ rslt_msb);
+ if (rc < 0) {
+ pr_err("qpnp iadc configure error for MSB write\n");
+ goto fail;
+ }
+
+ rc = qpnp_iadc_write_reg(QPNP_IADC_SEC_ACCESS,
+ QPNP_IADC_SEC_ACCESS_DATA);
+ if (rc < 0) {
+ pr_err("qpnp iadc configure error for sec access\n");
+ goto fail;
+ }
+
+ rc = qpnp_iadc_write_reg(QPNP_IADC_LSB_OFFSET,
+ rslt_lsb);
+ if (rc < 0) {
+ pr_err("qpnp iadc configure error for LSB write\n");
+ goto fail;
+ }
fail:
return rc;
}
+static void qpnp_iadc_work(struct work_struct *work)
+{
+ struct qpnp_iadc_drv *iadc = qpnp_iadc;
+ int rc = 0;
+
+ mutex_lock(&iadc->adc->adc_lock);
+
+ rc = qpnp_iadc_calibrate_for_trim();
+ if (rc)
+ pr_err("periodic IADC calibration failed\n");
+
+ mutex_unlock(&iadc->adc->adc_lock);
+
+ schedule_delayed_work(&iadc->iadc_work,
+ round_jiffies_relative(msecs_to_jiffies
+ (QPNP_IADC_CALIB_SECONDS)));
+
+ return;
+}
+
static int32_t qpnp_iadc_version_check(void)
{
uint8_t revision;
@@ -411,40 +510,102 @@
}
EXPORT_SYMBOL(qpnp_iadc_is_ready);
-int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
- int32_t *result)
+int32_t qpnp_iadc_get_rsense(int32_t *rsense)
+{
+ uint8_t rslt_rsense;
+ int32_t rc, sign_bit = 0;
+
+ rc = qpnp_iadc_read_reg(QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense);
+ if (rc < 0) {
+ pr_err("qpnp adc rsense read failed with %d\n", rc);
+ return rc;
+ }
+
+ if (rslt_rsense & QPNP_RSENSE_MSB_SIGN_CHECK)
+ sign_bit = 1;
+
+ rslt_rsense &= ~QPNP_RSENSE_MSB_SIGN_CHECK;
+
+ if (sign_bit)
+ *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR -
+ (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
+ else
+ *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR +
+ (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
+
+ return rc;
+}
+
+int32_t qpnp_check_pmic_temp(void)
{
struct qpnp_iadc_drv *iadc = qpnp_iadc;
- int32_t vsense_mv = 0, rc;
+ struct qpnp_vadc_result result_pmic_therm;
+ int rc;
+
+ rc = qpnp_vadc_read(DIE_TEMP, &result_pmic_therm);
+ if (rc < 0)
+ return rc;
+
+ if (((uint64_t) (result_pmic_therm.physical -
+ iadc->die_temp_calib_offset))
+ > QPNP_IADC_DIE_TEMP_CALIB_OFFSET) {
+ mutex_lock(&iadc->adc->adc_lock);
+
+ rc = qpnp_iadc_calibrate_for_trim();
+ if (rc)
+ pr_err("periodic IADC calibration failed\n");
+
+ mutex_unlock(&iadc->adc->adc_lock);
+ }
+
+ return 0;
+}
+
+int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
+ struct qpnp_iadc_result *result)
+{
+ struct qpnp_iadc_drv *iadc = qpnp_iadc;
+ int32_t rc, rsense_n_ohms, sign = 0, num;
+ int64_t result_current;
+ uint16_t raw_data;
if (!iadc || !iadc->iadc_initialized)
return -EPROBE_DEFER;
- mutex_lock(&iadc->adc->adc_lock);
-
- if (!iadc->iadc_init_calib) {
- rc = qpnp_iadc_version_check();
- if (rc)
- goto fail;
- rc = qpnp_iadc_init_calib();
- if (rc) {
- pr_err("Calibration failed\n");
- goto fail;
- } else
- iadc->iadc_init_calib = true;
+ rc = qpnp_check_pmic_temp();
+ if (rc) {
+ pr_err("Error checking pmic therm temp\n");
+ return rc;
}
- rc = qpnp_iadc_configure(channel, result);
+ mutex_lock(&iadc->adc->adc_lock);
+
+ rc = qpnp_iadc_configure(channel, &raw_data);
if (rc < 0) {
pr_err("qpnp adc result read failed with %d\n", rc);
goto fail;
}
- *result = ((vsense_mv - iadc->adc->calib.offset) *
- QPNP_ADC_GAIN_CALCULATION_UV)/
- (iadc->adc->calib.gain - iadc->adc->calib.offset);
+ rc = qpnp_iadc_get_rsense(&rsense_n_ohms);
- *result = (*result / (qpnp_iadc->rsense));
+ num = raw_data - iadc->adc->calib.offset_raw;
+ if (num < 0) {
+ sign = 1;
+ num = -num;
+ }
+
+ result->result_uv = (num * QPNP_ADC_GAIN_NV)/
+ (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
+ result_current = result->result_uv;
+ result_current *= QPNP_IADC_NANO_VOLTS_FACTOR;
+ do_div(result_current, rsense_n_ohms);
+
+ if (sign) {
+ result->result_uv = -result->result_uv;
+ result_current = -result_current;
+ }
+
+ result->result_ua = (int32_t) result_current;
fail:
mutex_unlock(&iadc->adc->adc_lock);
@@ -452,24 +613,39 @@
}
EXPORT_SYMBOL(qpnp_iadc_read);
-int32_t qpnp_iadc_get_gain(int32_t *result)
+int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_calib *result)
{
- return qpnp_iadc_read(GAIN_CALIBRATION_25MV, result);
-}
-EXPORT_SYMBOL(qpnp_iadc_get_gain);
+ struct qpnp_iadc_drv *iadc = qpnp_iadc;
+ int rc;
-int32_t qpnp_iadc_get_offset(enum qpnp_iadc_channels channel,
- int32_t *result)
-{
- return qpnp_iadc_read(channel, result);
+ if (!iadc || !iadc->iadc_initialized)
+ return -EPROBE_DEFER;
+
+ rc = qpnp_check_pmic_temp();
+ if (rc) {
+ pr_err("Error checking pmic therm temp\n");
+ return rc;
+ }
+
+ mutex_lock(&iadc->adc->adc_lock);
+ result->gain_raw = iadc->adc->calib.gain_raw;
+ result->ideal_gain_nv = QPNP_ADC_GAIN_NV;
+ result->gain_uv = iadc->adc->calib.gain_uv;
+ result->offset_raw = iadc->adc->calib.offset_raw;
+ result->ideal_offset_uv =
+ QPNP_OFFSET_CALIBRATION_SHORT_CADC_LEADS_IDEAL;
+ result->offset_uv = iadc->adc->calib.offset_uv;
+ mutex_unlock(&iadc->adc->adc_lock);
+
+ return 0;
}
-EXPORT_SYMBOL(qpnp_iadc_get_offset);
+EXPORT_SYMBOL(qpnp_iadc_get_gain_and_offset);
static ssize_t qpnp_iadc_show(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- int32_t result;
+ struct qpnp_iadc_result result;
int rc = -1;
rc = qpnp_iadc_read(attr->index, &result);
@@ -478,7 +654,7 @@
return 0;
return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
- "Result:%d\n", result);
+ "Result:%d\n", result.result_ua);
}
static struct sensor_device_attribute qpnp_adc_attr =
@@ -592,10 +768,28 @@
rc = qpnp_iadc_configure_interrupt();
if (rc) {
- dev_err(&spmi->dev, "failed to configure interrupt");
+ dev_err(&spmi->dev, "failed to configure interrupt\n");
return rc;
}
+ rc = qpnp_iadc_version_check();
+ if (rc) {
+ dev_err(&spmi->dev, "IADC version not supported\n");
+ return rc;
+ }
+
+ rc = qpnp_iadc_calibrate_for_trim();
+ if (rc) {
+ dev_err(&spmi->dev, "failed to calibrate for USR trim\n");
+ return rc;
+ }
+ iadc->iadc_init_calib = true;
+ INIT_DELAYED_WORK(&iadc->iadc_work, qpnp_iadc_work);
+ schedule_delayed_work(&iadc->iadc_work,
+ round_jiffies_relative(msecs_to_jiffies
+ (QPNP_IADC_CALIB_SECONDS)));
+ iadc->iadc_initialized = true;
+
return 0;
}
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 13493b8..696c9f9 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -1,5 +1,5 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -68,8 +68,6 @@
#define WLED_SYNC_VAL 0x07
#define WLED_SYNC_RESET_VAL 0x00
-#define WLED_TRIGGER_DEFAULT "none"
-#define WLED_FLAGS_DEFAULT 0x00
#define WLED_DEFAULT_STRINGS 0x01
#define WLED_DEFAULT_OVP_VAL 0x02
#define WLED_BOOST_LIM_DEFAULT 0x03
@@ -77,6 +75,8 @@
#define WLED_CTRL_DLY_DEFAULT 0x00
#define WLED_SWITCH_FREQ_DEFAULT 0x02
+#define LED_TRIGGER_DEFAULT "none"
+
/**
* enum qpnp_leds - QPNP supported led ids
* @QPNP_ID_WLED - White led backlight
@@ -119,9 +119,9 @@
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
/* LED1 */
0x60, 0x61, 0x62, 0x63, 0x66,
- /* LED1 */
+ /* LED2 */
0x70, 0x71, 0x72, 0x73, 0x76,
- /* LED1 */
+ /* LED3 */
0x80, 0x81, 0x82, 0x83, 0x86,
};
@@ -155,6 +155,7 @@
* @base_reg - base register given in device tree
* @lock - to protect the transactions
* @reg - cached value of led register
+ * @num_leds - number of leds in the module
* @max_current - maximum current supported by LED
* @default_on - true: default state max, false, default state 0
*/
@@ -164,6 +165,7 @@
int id;
u16 base;
u8 reg;
+ u8 num_leds;
spinlock_t lock;
struct wled_config_data *wled_cfg;
int max_current;
@@ -194,6 +196,22 @@
return rc;
}
+static void qpnp_dump_regs(struct qpnp_led_data *led, u8 regs[], u8 array_size)
+{
+ int i;
+ u8 val;
+
+ pr_debug("===== %s LED register dump start =====\n", led->cdev.name);
+ for (i = 0; i < array_size; i++) {
+ spmi_ext_register_readl(led->spmi_dev->ctrl,
+ led->spmi_dev->sid,
+ led->base + regs[i],
+ &val, sizeof(val));
+ pr_debug("0x%x = 0x%x\n", led->base + regs[i], val);
+ }
+ pr_debug("===== %s LED register dump end =====\n", led->cdev.name);
+}
+
static int qpnp_wled_set(struct qpnp_led_data *led)
{
int rc, duty;
@@ -271,22 +289,6 @@
return 0;
}
-static void qpnp_wled_dump_regs(struct qpnp_led_data *led)
-{
- int i;
- u8 val;
-
- pr_debug("===== WLED register dump start =====\n");
- for (i = 0; i < ARRAY_SIZE(wled_debug_regs); i++) {
- spmi_ext_register_readl(led->spmi_dev->ctrl,
- led->spmi_dev->sid,
- led->base + wled_debug_regs[i],
- &val, sizeof(val));
- pr_debug("0x%x = 0x%x\n", led->base + wled_debug_regs[i], val);
- }
- pr_debug("===== WLED register dump end =====\n");
-}
-
static void qpnp_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
@@ -294,9 +296,8 @@
struct qpnp_led_data *led;
led = container_of(led_cdev, struct qpnp_led_data, cdev);
-
if (value < LED_OFF || value > led->cdev.max_brightness) {
- dev_err(led->cdev.dev, "Invalid brightness value\n");
+ dev_err(&led->spmi_dev->dev, "Invalid brightness value\n");
return;
}
@@ -307,11 +308,11 @@
case QPNP_ID_WLED:
rc = qpnp_wled_set(led);
if (rc < 0)
- dev_err(led->cdev.dev,
+ dev_err(&led->spmi_dev->dev,
"WLED set brightness failed (%d)\n", rc);
break;
default:
- dev_err(led->cdev.dev, "Invalid LED(%d)\n", led->id);
+ dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
break;
}
spin_unlock(&led->lock);
@@ -324,7 +325,7 @@
led->cdev.max_brightness = WLED_MAX_LEVEL;
break;
default:
- dev_err(led->cdev.dev, "Invalid LED(%d)\n", led->id);
+ dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
return -EINVAL;
}
@@ -465,7 +466,7 @@
}
/* dump wled registers */
- qpnp_wled_dump_regs(led);
+ qpnp_dump_regs(led, wled_debug_regs, ARRAY_SIZE(wled_debug_regs));
return 0;
}
@@ -478,17 +479,43 @@
case QPNP_ID_WLED:
rc = qpnp_wled_init(led);
if (rc)
- dev_err(led->cdev.dev,
+ dev_err(&led->spmi_dev->dev,
"WLED initialize failed(%d)\n", rc);
break;
default:
- dev_err(led->cdev.dev, "Invalid LED(%d)\n", led->id);
+ dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
rc = -EINVAL;
}
return rc;
}
+static int __devinit qpnp_get_common_configs(struct qpnp_led_data *led,
+ struct device_node *node)
+{
+ int rc;
+ const char *temp_string;
+
+ led->cdev.default_trigger = LED_TRIGGER_DEFAULT;
+ rc = of_property_read_string(node, "linux,default-trigger",
+ &temp_string);
+ if (!rc)
+ led->cdev.default_trigger = temp_string;
+ else if (rc != -EINVAL)
+ return rc;
+
+ led->default_on = false;
+ rc = of_property_read_string(node, "qcom,default-state",
+ &temp_string);
+ if (!rc) {
+ if (strncmp(temp_string, "on", sizeof("on")) == 0)
+ led->default_on = true;
+ } else if (rc != -EINVAL)
+ return rc;
+
+ return 0;
+}
+
/*
* Handlers for alternative sources of platform_data
*/
@@ -497,9 +524,6 @@
{
u32 val;
int rc;
- const char *temp_string;
-
- led->id = QPNP_ID_WLED;
led->wled_cfg = devm_kzalloc(&led->spmi_dev->dev,
sizeof(struct wled_config_data), GFP_KERNEL);
@@ -508,31 +532,6 @@
return -ENOMEM;
}
- led->cdev.default_trigger = WLED_TRIGGER_DEFAULT;
- rc = of_property_read_string(node, "linux,default-trigger",
- &temp_string);
- if (!rc)
- led->cdev.default_trigger = temp_string;
- else if (rc != -EINVAL)
- return rc;
-
-
- led->cdev.flags = WLED_FLAGS_DEFAULT;
- rc = of_property_read_u32(node, "qcom,flags", &val);
- if (!rc)
- led->cdev.flags = (int) val;
- else if (rc != -EINVAL)
- return rc;
-
- led->default_on = true;
- rc = of_property_read_string(node, "qcom,default-state",
- &temp_string);
- if (!rc) {
- if (!strncmp(temp_string, "off", sizeof("off")))
- led->default_on = false;
- } else if (rc != -EINVAL)
- return rc;
-
led->wled_cfg->num_strings = WLED_DEFAULT_STRINGS;
rc = of_property_read_u32(node, "qcom,num-strings", &val);
if (!rc)
@@ -591,105 +590,135 @@
{
struct qpnp_led_data *led;
struct resource *led_resource;
- struct device_node *node;
- int rc;
+ struct device_node *node, *temp;
+ int rc, i, num_leds = 0;
const char *led_label;
- led = devm_kzalloc(&spmi->dev, (sizeof(struct qpnp_led_data)),
- GFP_KERNEL);
+ node = spmi->dev.of_node;
+ if (node == NULL)
+ return -ENODEV;
+
+ temp = NULL;
+ while ((temp = of_get_next_child(node, temp)))
+ num_leds++;
+
+ led = devm_kzalloc(&spmi->dev,
+ (sizeof(struct qpnp_led_data) * num_leds), GFP_KERNEL);
if (!led) {
dev_err(&spmi->dev, "Unable to allocate memory\n");
return -ENOMEM;
}
- led->spmi_dev = spmi;
+ led->num_leds = num_leds;
+ num_leds = 0;
- led_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
- if (!led_resource) {
- dev_err(&spmi->dev, "Unable to get LED base address\n");
- return -ENXIO;
- }
- led->base = led_resource->start;
+ for_each_child_of_node(node, temp) {
+ led->spmi_dev = spmi;
- dev_set_drvdata(&spmi->dev, led);
+ led_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
+ if (!led_resource) {
+ dev_err(&spmi->dev, "Unable to get LED base address\n");
+ return -ENXIO;
+ }
+ led->base = led_resource->start;
- node = led->spmi_dev->dev.of_node;
- if (node == NULL)
- return -ENODEV;
+ dev_set_drvdata(&spmi->dev, led);
- rc = of_property_read_string(node, "qcom,label", &led_label);
- if (rc < 0) {
- dev_err(&led->spmi_dev->dev,
- "Failure reading label, rc = %d\n", rc);
- return rc;
- }
- rc = of_property_read_string(node, "qcom,name", &led->cdev.name);
- if (rc < 0) {
- dev_err(&led->spmi_dev->dev,
- "Failure reading led name, rc = %d\n", rc);
- return rc;
- }
-
- rc = of_property_read_u32(node, "qcom,max-current", &led->max_current);
- if (rc < 0) {
- dev_err(&led->spmi_dev->dev,
- "Failure reading max_current, rc = %d\n", rc);
- return rc;
- }
-
- led->cdev.brightness_set = qpnp_led_set;
- led->cdev.brightness_get = qpnp_led_get;
- led->cdev.brightness = LED_OFF;
-
- if (strncmp(led_label, "wled", sizeof("wled")) == 0) {
- rc = qpnp_get_config_wled(led, node);
+ rc = of_property_read_string(temp, "label", &led_label);
if (rc < 0) {
dev_err(&led->spmi_dev->dev,
- "Unable to read wled config data\n");
+ "Failure reading label, rc = %d\n", rc);
return rc;
}
- } else {
- dev_err(&led->spmi_dev->dev, "No LED matching label\n");
- return -EINVAL;
+
+ rc = of_property_read_string(temp, "linux,name",
+ &led->cdev.name);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev,
+ "Failure reading led name, rc = %d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32(temp, "qcom,max-current",
+ &led->max_current);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev,
+ "Failure reading max_current, rc = %d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32(temp, "qcom,id", &led->id);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev,
+ "Failure reading led id, rc = %d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_get_common_configs(led, temp);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Failure reading common led configuration," \
+ " rc = %d\n", rc);
+ return rc;
+ }
+
+ led->cdev.brightness_set = qpnp_led_set;
+ led->cdev.brightness_get = qpnp_led_get;
+
+ if (strncmp(led_label, "wled", sizeof("wled")) == 0) {
+ rc = qpnp_get_config_wled(led, temp);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev,
+ "Unable to read wled config data\n");
+ return rc;
+ }
+ } else {
+ dev_err(&led->spmi_dev->dev, "No LED matching label\n");
+ return -EINVAL;
+ }
+
+ spin_lock_init(&led->lock);
+
+ rc = qpnp_led_initialize(led);
+ if (rc < 0)
+ goto fail_id_check;
+
+ rc = qpnp_led_set_max_brightness(led);
+ if (rc < 0)
+ goto fail_id_check;
+
+ rc = led_classdev_register(&spmi->dev, &led->cdev);
+ if (rc) {
+ dev_err(&spmi->dev, "unable to register led %d,rc=%d\n",
+ led->id, rc);
+ goto fail_id_check;
+ }
+ /* configure default state */
+ if (led->default_on)
+ led->cdev.brightness = led->cdev.max_brightness;
+ else
+ led->cdev.brightness = LED_OFF;
+
+ qpnp_led_set(&led->cdev, led->cdev.brightness);
+ led++;
+ num_leds++;
}
-
- spin_lock_init(&led->lock);
-
- rc = qpnp_led_initialize(led);
- if (rc < 0)
- goto fail_id_check;
-
- rc = qpnp_led_set_max_brightness(led);
- if (rc < 0)
- goto fail_id_check;
-
-
- rc = led_classdev_register(&spmi->dev, &led->cdev);
- if (rc) {
- dev_err(&spmi->dev, "unable to register led %d,rc=%d\n",
- led->id, rc);
- goto fail_id_check;
- }
-
- /* configure default state */
- if (led->default_on)
- led->cdev.brightness = led->cdev.max_brightness;
-
- qpnp_led_set(&led->cdev, led->cdev.brightness);
-
return 0;
fail_id_check:
- led_classdev_unregister(&led->cdev);
+ for (i = 0; i < num_leds; i++)
+ led_classdev_unregister(&led[i].cdev);
return rc;
}
static int __devexit qpnp_leds_remove(struct spmi_device *spmi)
{
struct qpnp_led_data *led = dev_get_drvdata(&spmi->dev);
+ int i;
- led_classdev_unregister(&led->cdev);
+ for (i = 0; i < led->num_leds; i++)
+ led_classdev_unregister(&led[i].cdev);
return 0;
}
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index d9f62ad..cbd3b38 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -98,6 +98,18 @@
return index;
}
+static inline int dvb_dmxdev_events_is_full(struct dmxdev_events_queue *events)
+{
+ int new_write_index;
+
+ new_write_index = dvb_dmxdev_advance_event_idx(events->write_index);
+ if (new_write_index == events->read_index)
+ return 1;
+
+ return 0;
+
+}
+
static inline void dvb_dmxdev_flush_events(struct dmxdev_events_queue *events)
{
events->read_index = 0;
@@ -788,6 +800,13 @@
spin_lock_irq(&dmxdev->lock);
dvb_dmxdev_update_events(&dmxdev->dvr_output_events, res);
spin_unlock_irq(&dmxdev->lock);
+
+ /*
+ * in PULL mode, we might be stalling on
+ * event queue, so need to wake-up waiters
+ */
+ if (dmxdev->playback_mode == DMX_PB_MODE_PULL)
+ wake_up_all(&dmxdev->dvr_buffer.queue);
} else if (res == -EOVERFLOW) {
/*
* When buffer overflowed, demux-dev flushed the
@@ -1037,6 +1056,13 @@
spin_unlock_irq(&dmxdev->lock);
+ /*
+ * in PULL mode, we might be stalling on
+ * event queue, so need to wake-up waiters
+ */
+ if (dmxdev->playback_mode == DMX_PB_MODE_PULL)
+ wake_up_all(&dmxdev->dvr_buffer.queue);
+
return res;
}
@@ -1303,13 +1329,17 @@
{
struct dmxdev_filter *dmxdevfilter = filter->priv;
struct dvb_ringbuffer *src;
+ struct dmxdev_events_queue *events;
int ret;
if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
- || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
+ || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) {
src = &dmxdevfilter->buffer;
- else
+ events = &dmxdevfilter->events;
+ } else {
src = &dmxdevfilter->dev->dvr_buffer;
+ events = &dmxdevfilter->dev->dvr_output_events;
+ }
do {
ret = 0;
@@ -1330,7 +1360,8 @@
return ret;
}
- if (required_space <= dvb_ringbuffer_free(src)) {
+ if ((required_space <= dvb_ringbuffer_free(src)) &&
+ (!dvb_dmxdev_events_is_full(events))) {
spin_unlock(&dmxdevfilter->dev->lock);
return 0;
}
@@ -1339,7 +1370,8 @@
ret = wait_event_interruptible(src->queue,
(!src->data) ||
- (dvb_ringbuffer_free(src) >= required_space) ||
+ ((dvb_ringbuffer_free(src) >= required_space) &&
+ (!dvb_dmxdev_events_is_full(events))) ||
(src->error != 0) ||
(dmxdevfilter->state != DMXDEV_STATE_GO) ||
dmxdevfilter->dev->dvr_in_exit);
@@ -1355,6 +1387,7 @@
{
struct dmxdev_filter *dmxdevfilter = filter->priv;
struct dvb_ringbuffer *src = &dmxdevfilter->buffer;
+ struct dmxdev_events_queue *events = &dmxdevfilter->events;
int ret;
do {
@@ -1376,7 +1409,8 @@
return ret;
}
- if (required_space <= dvb_ringbuffer_free(src)) {
+ if ((required_space <= dvb_ringbuffer_free(src)) &&
+ (!dvb_dmxdev_events_is_full(events))) {
spin_unlock(&dmxdevfilter->dev->lock);
return 0;
}
@@ -1385,7 +1419,8 @@
ret = wait_event_interruptible(src->queue,
(!src->data) ||
- (dvb_ringbuffer_free(src) >= required_space) ||
+ ((dvb_ringbuffer_free(src) >= required_space) &&
+ (!dvb_dmxdev_events_is_full(events))) ||
(src->error != 0) ||
(dmxdevfilter->state != DMXDEV_STATE_GO) ||
dmxdevfilter->dev->dvr_in_exit);
@@ -1537,6 +1572,13 @@
spin_unlock_irq(&dmxdevfilter->dev->lock);
+ /*
+ * in PULL mode, we might be stalling on
+ * event queue, so need to wake-up waiters
+ */
+ if (dmxdevfilter->dev->playback_mode == DMX_PB_MODE_PULL)
+ wake_up_all(&dmxdevfilter->buffer.queue);
+
return res;
}
@@ -2608,6 +2650,13 @@
spin_lock_irq(&dmxdevfilter->dev->lock);
dvb_dmxdev_update_events(&dmxdevfilter->events, ret);
spin_unlock_irq(&dmxdevfilter->dev->lock);
+
+ /*
+ * in PULL mode, we might be stalling on
+ * event queue, so need to wake-up waiters
+ */
+ if (dmxdevfilter->dev->playback_mode == DMX_PB_MODE_PULL)
+ wake_up_all(&dmxdevfilter->buffer.queue);
} else if (ret == -EOVERFLOW) {
/*
* When buffer overflowed, demux-dev flushed the
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
index 627c5a2..2e783f6 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
@@ -30,15 +30,16 @@
#define DMX_TSIF_CHUNKS_IN_BUF 16
#define DMX_TSIF_TIME_LIMIT 10000
-/* TSIF_DRIVER_MODE: 3 means manual control from debugfs. use 1 normally. */
-#define DMX_TSIF_DRIVER_MODE_DEF 1
-
+/* TSIF_DRIVER_MODE: 3 means manual control from debugfs. use 2 normally. */
+#define DMX_TSIF_DRIVER_MODE_DEF 2
/* module parameters for load time configuration: */
static int threshold = DMX_TSIF_PACKETS_IN_CHUNK_DEF;
-static int mode = DMX_TSIF_DRIVER_MODE_DEF;
+static int tsif_mode = DMX_TSIF_DRIVER_MODE_DEF;
+static int clock_inv;
module_param(threshold, int, S_IRUGO);
-module_param(mode, int, S_IRUGO);
+module_param(tsif_mode, int, S_IRUGO);
+module_param(clock_inv, int, S_IRUGO);
/*
* Work scheduled each time TSIF notifies dmx
@@ -273,7 +274,6 @@
tsif_driver = &(mpq_dmx_tsif_info.tsif[tsif].tsif_driver);
/* Attach to TSIF driver */
-
tsif_driver->tsif_handler =
tsif_attach(tsif, mpq_tsif_callback, (void *)tsif);
if (IS_ERR_OR_NULL(tsif_driver->tsif_handler)) {
@@ -284,12 +284,19 @@
return -ENODEV;
}
+ ret = tsif_set_clk_inverse(tsif_driver->tsif_handler,
+ clock_inv);
+ if (ret < 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: tsif_set_clk_inverse (%d) failed\n",
+ __func__, clock_inv);
+ }
+
/* Set TSIF driver mode */
- ret = tsif_set_mode(tsif_driver->tsif_handler,
- mode);
+ ret = tsif_set_mode(tsif_driver->tsif_handler, tsif_mode);
if (ret < 0) {
MPQ_DVB_ERR_PRINT("%s: tsif_set_mode (%d) failed\n",
- __func__, mode);
+ __func__, tsif_mode);
}
/* Set TSIF buffer configuration */
@@ -304,18 +311,6 @@
MPQ_DVB_ERR_PRINT("Using default TSIF driver values\n");
}
-
- /* Set TSIF driver time limit */
- /* TODO: needed?? */
-/* ret = tsif_set_time_limit(tsif_driver->tsif_handler,
- DMX_TSIF_TIME_LIMIT);
- if (ret < 0) {
- MPQ_DVB_ERR_PRINT(
- "%s: tsif_set_time_limit (%d) failed\n",
- __func__, DMX_TSIF_TIME_LIMIT);
- }
-*/
-
/* Start TSIF driver */
ret = tsif_start(tsif_driver->tsif_handler);
if (ret < 0) {
@@ -705,11 +700,11 @@
__func__, DMX_TSIF_PACKETS_IN_CHUNK_DEF);
threshold = DMX_TSIF_PACKETS_IN_CHUNK_DEF;
}
- if ((mode < 1) || (mode > 3)) {
+ if ((tsif_mode < 1) || (tsif_mode > 3)) {
MPQ_DVB_ERR_PRINT(
"%s: invalid mode parameter, using %d instead\n",
__func__, DMX_TSIF_DRIVER_MODE_DEF);
- mode = DMX_TSIF_DRIVER_MODE_DEF;
+ tsif_mode = DMX_TSIF_DRIVER_MODE_DEF;
}
for (i = 0; i < TSIF_COUNT; i++) {
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
index 68af7e1..191a0c4 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
@@ -66,10 +66,10 @@
#define TSPP_CHANNEL_TIMEOUT 16
/* module parameters for load time configuration */
-static int tsif0_mode = TSPP_TSIF_MODE_2;
-static int tsif1_mode = TSPP_TSIF_MODE_2;
-module_param(tsif0_mode, int, S_IRUGO);
-module_param(tsif1_mode, int, S_IRUGO);
+static int clock_inv;
+static int tsif_mode = 2;
+module_param(tsif_mode, int, S_IRUGO);
+module_param(clock_inv, int, S_IRUGO);
/*
* Work scheduled each time TSPP notifies dmx
@@ -279,20 +279,30 @@
int channel_id;
int *channel_ref_count;
- tspp_source.clk_inverse = 0;
+ tspp_source.clk_inverse = clock_inv;
tspp_source.data_inverse = 0;
tspp_source.sync_inverse = 0;
tspp_source.enable_inverse = 0;
+ switch (tsif_mode) {
+ case 1:
+ tspp_source.mode = TSPP_TSIF_MODE_1;
+ break;
+ case 2:
+ tspp_source.mode = TSPP_TSIF_MODE_2;
+ break;
+ default:
+ tspp_source.mode = TSPP_TSIF_MODE_LOOPBACK;
+ break;
+ }
+
/* determine the TSIF we are reading from */
if (mpq_demux->source == DMX_SOURCE_FRONT0) {
tsif = 0;
tspp_source.source = TSPP_SOURCE_TSIF0;
- tspp_source.mode = (enum tspp_tsif_mode)tsif0_mode;
} else if (mpq_demux->source == DMX_SOURCE_FRONT1) {
tsif = 1;
tspp_source.source = TSPP_SOURCE_TSIF1;
- tspp_source.mode = (enum tspp_tsif_mode)tsif1_mode;
} else {
/* invalid source */
MPQ_DVB_ERR_PRINT(
diff --git a/drivers/media/dvb/mpq/video/mpq_dvb_video.c b/drivers/media/dvb/mpq/video/mpq_dvb_video.c
index 22d37e9..229a81a 100644
--- a/drivers/media/dvb/mpq/video/mpq_dvb_video.c
+++ b/drivers/media/dvb/mpq/video/mpq_dvb_video.c
@@ -53,6 +53,7 @@
"dvb-vid-3",
};
+static enum scan_format map_scan_type(enum vdec_interlaced_format type);
static int mpq_int_vid_dec_decode_frame(struct video_client_ctx *client_ctx,
struct video_data_buffer *input_frame);
static int mpq_int_vid_dec_get_buffer_req(struct video_client_ctx *client_ctx,
@@ -2120,6 +2121,8 @@
vdec_msg_info.msgdata.output_frame.time_stamp;
ev->u.buffer.offset =
vdec_msg_info.msgdata.output_frame.offset;
+ ev->u.buffer.interlaced_format = map_scan_type(vdec_msg_info.\
+ msgdata.output_frame.interlaced_format);
break;
case VDEC_MSG_RESP_START_DONE:
DBG("VIDEO_EVENT_DECODER_PLAYING\n");
@@ -2161,6 +2164,8 @@
vdec_msg_info.msgdata.output_frame.time_stamp;
ev->u.buffer.offset =
vdec_msg_info.msgdata.output_frame.offset;
+ ev->u.buffer.interlaced_format = map_scan_type(vdec_msg_info.\
+ msgdata.output_frame.interlaced_format);
break;
case VDEC_MSG_RESP_FLUSH_INPUT_DONE:
DBG("VIDEO_EVENT_INPUT_FLUSH_DONE\n");
@@ -2176,6 +2181,17 @@
return 0;
}
+static enum scan_format map_scan_type(enum vdec_interlaced_format type)
+{
+ if (type == VDEC_InterlaceFrameProgressive)
+ return INTERLACE_FRAME_PROGRESSIVE;
+ if (type == VDEC_InterlaceInterleaveFrameTopFieldFirst)
+ return INTERLACE_INTERLEAVE_FRAME_TOP_FIELD_FIRST;
+ if (type == VDEC_InterlaceInterleaveFrameBottomFieldFirst)
+ return INTERLACE_INTERLEAVE_FRAME_BOTTOM_FIELD_FIRST;
+ return INTERLACE_FRAME_PROGRESSIVE;
+}
+
static int mpq_dvb_video_play(struct mpq_dvb_video_inst *dev_inst)
{
return mpq_int_vid_dec_start_stop(dev_inst->client_ctx, true);
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index 7d44fea..80fdac5 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -671,7 +671,6 @@
if (rc)
dprintk(VIDC_WARN,
"Failed in %s for release output buffers\n", __func__);
- rc = msm_vidc_close(vidc_inst);
list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
bi = list_entry(ptr, struct buffer_info, list);
if (bi->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
@@ -686,6 +685,7 @@
}
}
msm_smem_delete_client(v4l2_inst->mem_client);
+ rc = msm_vidc_close(vidc_inst);
kfree(v4l2_inst);
return rc;
}
@@ -777,6 +777,11 @@
goto exit;
}
for (i = 0; i < b->length; ++i) {
+ if (EXTRADATA_IDX(b->length) &&
+ (i == EXTRADATA_IDX(b->length)) &&
+ !b->m.planes[i].length) {
+ continue;
+ }
temp = get_registered_buf(&v4l2_inst->registered_bufs,
b->m.planes[i].reserved[0],
b->m.planes[i].reserved[1],
@@ -850,6 +855,12 @@
vidc_inst = get_vidc_inst(file, fh);
v4l2_inst = get_v4l2_inst(file, fh);
for (i = 0; i < b->length; ++i) {
+ if (EXTRADATA_IDX(b->length) &&
+ (i == EXTRADATA_IDX(b->length)) &&
+ !b->m.planes[i].length) {
+ b->m.planes[i].m.userptr = 0;
+ continue;
+ }
binfo = get_registered_buf(&v4l2_inst->registered_bufs,
b->m.planes[i].reserved[0],
b->m.planes[i].reserved[1],
@@ -902,6 +913,11 @@
goto fail_dq_buf;
}
for (i = 0; i < b->length; i++) {
+ if (EXTRADATA_IDX(b->length) &&
+ (i == EXTRADATA_IDX(b->length)) &&
+ !b->m.planes[i].m.userptr) {
+ continue;
+ }
b->m.planes[i].m.userptr = device_to_uvaddr(
&v4l2_inst->registered_bufs,
b->m.planes[i].m.userptr);
@@ -958,17 +974,35 @@
rc = msm_v4l2_release_output_buffers(v4l2_inst);
if (rc)
dprintk(VIDC_WARN,
- "Failed in %s for release output buffers\n", __func__);
+ "Failed to release dec output buffers: %d\n", rc);
return msm_vidc_decoder_cmd((void *)vidc_inst, dec);
}
static int msm_v4l2_encoder_cmd(struct file *file, void *fh,
struct v4l2_encoder_cmd *enc)
{
+ struct msm_v4l2_vid_inst *v4l2_inst;
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ int rc = 0;
+ v4l2_inst = get_v4l2_inst(file, NULL);
+ if (enc->cmd == V4L2_ENC_CMD_STOP)
+ rc = msm_v4l2_release_output_buffers(v4l2_inst);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed to release enc output buffers: %d\n", rc);
return msm_vidc_encoder_cmd((void *)vidc_inst, enc);
}
-
+static int msm_v4l2_s_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_s_parm((void *)vidc_inst, a);
+}
+static int msm_v4l2_g_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a)
+{
+ return 0;
+}
static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
.vidioc_querycap = msm_v4l2_querycap,
.vidioc_enum_fmt_vid_cap_mplane = msm_v4l2_enum_fmt,
@@ -989,6 +1023,8 @@
.vidioc_unsubscribe_event = msm_v4l2_unsubscribe_event,
.vidioc_decoder_cmd = msm_v4l2_decoder_cmd,
.vidioc_encoder_cmd = msm_v4l2_encoder_cmd,
+ .vidioc_s_parm = msm_v4l2_s_parm,
+ .vidioc_g_parm = msm_v4l2_g_parm
};
static const struct v4l2_ioctl_ops msm_v4l2_enc_ioctl_ops = {
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index 058c835..b476e39 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -346,7 +346,8 @@
buffer_info.align_device_addr =
b->m.planes[0].m.userptr;
extra_idx = EXTRADATA_IDX(b->length);
- if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES) &&
+ b->m.planes[extra_idx].m.userptr) {
buffer_info.extradata_addr =
b->m.planes[extra_idx].m.userptr;
dprintk(VIDC_DBG,
@@ -354,6 +355,9 @@
b->m.planes[extra_idx].m.userptr);
buffer_info.extradata_size =
b->m.planes[extra_idx].length;
+ } else {
+ buffer_info.extradata_addr = 0;
+ buffer_info.extradata_size = 0;
}
rc = vidc_hal_session_set_buffers((void *)inst->session,
&buffer_info);
@@ -409,9 +413,13 @@
buffer_info.align_device_addr =
b->m.planes[0].m.userptr;
extra_idx = EXTRADATA_IDX(b->length);
- if (extra_idx && (extra_idx < VIDEO_MAX_PLANES))
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)
+ && b->m.planes[extra_idx].m.userptr)
buffer_info.extradata_addr =
b->m.planes[extra_idx].m.userptr;
+ else
+ buffer_info.extradata_addr = 0;
+
rc = vidc_hal_session_release_buffers(
(void *)inst->session, &buffer_info);
if (rc)
@@ -544,7 +552,42 @@
}
return rc;
}
-
+int msm_vdec_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a)
+{
+ u32 us_per_frame = 0;
+ int rc = 0;
+ if (a->parm.output.timeperframe.denominator) {
+ switch (a->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ us_per_frame = a->parm.output.timeperframe.numerator/
+ a->parm.output.timeperframe.denominator;
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ us_per_frame = a->parm.capture.timeperframe.numerator/
+ a->parm.capture.timeperframe.denominator;
+ break;
+ default:
+ dprintk(VIDC_ERR,
+ "Scale clocks : Unknown buffer type\n");
+ break;
+ }
+ }
+ if (!us_per_frame) {
+ dprintk(VIDC_ERR,
+ "Failed to scale clocks : time between frames is 0\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+ inst->prop.fps = (u8) (USEC_PER_SEC / us_per_frame);
+ if (inst->prop.fps) {
+ if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
+ dprintk(VIDC_WARN,
+ "Failed to scale clocks\n");
+ }
+ }
+exit:
+ return rc;
+}
int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
{
const struct msm_vidc_format *fmt = NULL;
diff --git a/drivers/media/video/msm_vidc/msm_vdec.h b/drivers/media/video/msm_vidc/msm_vdec.h
index b8326d8..419c8c1 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.h
+++ b/drivers/media/video/msm_vidc/msm_vdec.h
@@ -32,6 +32,7 @@
int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
int msm_vdec_cmd(struct msm_vidc_inst *inst, struct v4l2_decoder_cmd *dec);
+int msm_vdec_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a);
struct vb2_ops *msm_vdec_get_vb2q_ops(void);
#endif
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 0ea2a60..3f892b1 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -1274,6 +1274,14 @@
v4l2_event_queue_fh(&inst->event_handler, &dqevent);
return rc;
}
+ rc = msm_comm_release_scratch_buffers(inst);
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to release scratch buf:%d\n",
+ rc);
+ rc = msm_comm_release_persist_buffers(inst);
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to release persist buf:%d\n",
+ rc);
rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
break;
}
@@ -1331,6 +1339,55 @@
return rc;
}
+int msm_venc_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a)
+{
+ u32 property_id = 0, us_per_frame = 0;
+ void *pdata;
+ int rc = 0;
+ struct hal_frame_rate frame_rate;
+ property_id = HAL_CONFIG_FRAME_RATE;
+ if (a->parm.output.timeperframe.denominator) {
+ switch (a->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ us_per_frame = a->parm.output.timeperframe.numerator/
+ a->parm.output.timeperframe.denominator;
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ us_per_frame = a->parm.capture.timeperframe.numerator/
+ a->parm.capture.timeperframe.denominator;
+ break;
+ default:
+ dprintk(VIDC_ERR,
+ "Scale clocks : Unknown buffer type\n");
+ break;
+ }
+ }
+
+ if (!us_per_frame) {
+ dprintk(VIDC_ERR,
+ "Failed to scale clocks : time between frames is 0\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+ inst->prop.fps = (u8) (USEC_PER_SEC / us_per_frame);
+ if (inst->prop.fps) {
+ frame_rate.frame_rate = inst->prop.fps * (0x1<<16);
+ frame_rate.buffer_type = HAL_BUFFER_OUTPUT;
+ pdata = &frame_rate;
+ rc = vidc_hal_session_set_property((void *)inst->session,
+ property_id, pdata);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed to set frame rate %d\n", rc);
+ }
+ if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
+ dprintk(VIDC_WARN,
+ "Failed to scale clocks\n");
+ }
+ }
+exit:
+ return rc;
+}
int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
{
const struct msm_vidc_format *fmt = NULL;
@@ -1507,6 +1564,43 @@
return rc;
}
+int msm_venc_release_buf(struct msm_vidc_inst *inst,
+ struct v4l2_buffer *b)
+{
+ int rc = 0;
+ int i;
+ struct vidc_buffer_addr_info buffer_info;
+
+ switch (b->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ for (i = 0; i < b->length; i++) {
+ dprintk(VIDC_DBG,
+ "Release device_addr = %ld, size = %d, %d\n",
+ b->m.planes[i].m.userptr,
+ b->m.planes[i].length, inst->state);
+ buffer_info.buffer_size = b->m.planes[i].length;
+ buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr =
+ b->m.planes[i].m.userptr;
+ buffer_info.extradata_size = 0;
+ buffer_info.extradata_addr = 0;
+ rc = vidc_hal_session_release_buffers(
+ (void *)inst->session, &buffer_info);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "vidc_hal_session_release_buffers failed\n");
+ }
+ break;
+ default:
+ dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
+ break;
+ }
+ return rc;
+}
+
int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
{
struct buf_queue *q = NULL;
diff --git a/drivers/media/video/msm_vidc/msm_venc.h b/drivers/media/video/msm_vidc/msm_venc.h
index 83610b3..ad63e7d 100644
--- a/drivers/media/video/msm_vidc/msm_venc.h
+++ b/drivers/media/video/msm_vidc/msm_venc.h
@@ -26,11 +26,13 @@
int msm_venc_g_ctrl(void *instance, struct v4l2_control *a);
int msm_venc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
int msm_venc_prepare_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_release_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
int msm_venc_cmd(struct msm_vidc_inst *inst, struct v4l2_encoder_cmd *enc);
+int msm_venc_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a);
struct vb2_ops *msm_venc_get_vb2q_ops(void);
#endif
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index 886113f..1d0124f 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -109,6 +109,19 @@
return msm_venc_querycap(instance, cap);
return -EINVAL;
}
+int msm_vidc_s_parm(void *instance,
+ struct v4l2_streamparm *a)
+{
+ struct msm_vidc_inst *inst = instance;
+
+ if (!inst || !a)
+ return -EINVAL;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_s_parm(instance, a);
+ else if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_s_parm(instance, a);
+ return -EINVAL;
+}
int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f)
{
struct msm_vidc_inst *inst = instance;
@@ -211,6 +224,8 @@
if (inst->session_type == MSM_VIDC_DECODER)
return msm_vdec_release_buf(instance, b);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_release_buf(instance, b);
return -EINVAL;
}
@@ -403,6 +418,8 @@
goto err_invalid_core;
}
+ pr_info(VIDC_DBG_TAG "Opening video instance: %p, %d\n",
+ VIDC_INFO, inst, session_type);
mutex_init(&inst->sync_lock);
mutex_init(&inst->bufq[CAPTURE_PORT].lock);
mutex_init(&inst->bufq[OUTPUT_PORT].lock);
@@ -538,14 +555,14 @@
list_del(&inst->list);
}
mutex_unlock(&core->sync_lock);
+ cleanup_instance(inst);
if (inst->state != MSM_VIDC_CORE_INVALID &&
core->state != VIDC_CORE_INVALID)
rc = msm_comm_try_state(inst, MSM_VIDC_CORE_UNINIT);
if (rc)
dprintk(VIDC_ERR,
"Failed to move video instance to uninit state\n");
- cleanup_instance(inst);
+ pr_info(VIDC_DBG_TAG "Closed video instance: %p\n", VIDC_INFO, inst);
kfree(inst);
- dprintk(VIDC_DBG, "Closed the instance\n");
return 0;
}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index 54c3d5f..56bcf65 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -528,6 +528,7 @@
dqevent.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
dqevent.id = 0;
v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+ inst->session = NULL;
wake_up(&inst->kernel_event_queue);
show_stats(inst);
} else {
@@ -1550,7 +1551,8 @@
frame_data.buffer_type = HAL_BUFFER_OUTPUT;
extra_idx =
EXTRADATA_IDX(inst->fmts[CAPTURE_PORT]->num_planes);
- if (extra_idx)
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES) &&
+ vb->v4l2_planes[extra_idx].m.userptr)
frame_data.extradata_addr =
vb->v4l2_planes[extra_idx].m.userptr;
dprintk(VIDC_DBG,
diff --git a/drivers/media/video/vcap_vc.c b/drivers/media/video/vcap_vc.c
index c7637b6..f3c9362 100644
--- a/drivers/media/video/vcap_vc.c
+++ b/drivers/media/video/vcap_vc.c
@@ -439,11 +439,10 @@
vc_format->mode << 10,
VCAP_VC_CTRL);
- writel_relaxed(vc_format->h_polar << 4 |
+ writel_relaxed(vc_format->d_polar << 8 |
+ vc_format->h_polar << 4 |
vc_format->v_polar << 0, VCAP_VC_POLARITY);
- writel_relaxed(vc_format->h_polar << 4 |
- vc_format->v_polar << 0, VCAP_VC_POLARITY);
writel_relaxed(((vc_format->htotal << 16) | vc_format->vtotal),
VCAP_VC_V_H_TOTAL);
writel_relaxed(((vc_format->hactive_end << 16) |
diff --git a/drivers/mfd/marimba-core.c b/drivers/mfd/marimba-core.c
index 6a8ea6e..d84bb7b 100644
--- a/drivers/mfd/marimba-core.c
+++ b/drivers/mfd/marimba-core.c
@@ -173,13 +173,14 @@
u8 data[num_bytes + 1];
u8 mask_value[num_bytes];
+ memset(mask_value, 0, sizeof(mask_value));
+
marimba = &marimba_modules[marimba->mod_id];
if (marimba == NULL) {
pr_err("%s: Unable to access Marimba core\n", __func__);
return -ENODEV;
}
-
mutex_lock(&marimba->xfer_lock);
for (i = 0; i < num_bytes; i++)
@@ -619,7 +620,7 @@
static int __devinit marimba_dbg_init(int adie_type)
{
struct adie_dbg_device *dbgdev;
- struct dentry *dent;
+ struct dentry *dent = NULL;
struct dentry *temp;
dbgdev = kzalloc(sizeof *dbgdev, GFP_KERNEL);
diff --git a/drivers/mfd/pm8xxx-spk.c b/drivers/mfd/pm8xxx-spk.c
index 8ba7372..4366717 100644
--- a/drivers/mfd/pm8xxx-spk.c
+++ b/drivers/mfd/pm8xxx-spk.c
@@ -118,8 +118,6 @@
}
val = pm8xxx_spk_read(PM8XXX_SPK_CTL1_REG_OFF);
- if (val < 0)
- return val;
val |= mute << 2;
ret = pm8xxx_spk_write(PM8XXX_SPK_CTL1_REG_OFF, val);
return ret;
@@ -137,8 +135,6 @@
}
val = pm8xxx_spk_read(PM8XXX_SPK_CTL1_REG_OFF);
- if (val < 0)
- return val;
val = (gain << 4) | (val & 0xF);
ret = pm8xxx_spk_write(PM8XXX_SPK_CTL1_REG_OFF, val);
if (!ret) {
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index a8e40f7..1f7b67a 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -550,6 +550,13 @@
}
wcd9xxx->num_of_supplies = 0;
+
+ if (ARRAY_SIZE(pdata->regulator) > MAX_REGULATOR) {
+ pr_err("%s: Array Size out of bound\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
if (pdata->regulator[i].name) {
wcd9xxx->supplies[i].supply = pdata->regulator[i].name;
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 53e965c..23e0fcc 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -56,6 +56,12 @@
struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
int i;
+ if (ARRAY_SIZE(wcd9xxx->irq_masks_cur) > WCD9XXX_NUM_IRQ_REGS ||
+ ARRAY_SIZE(wcd9xxx->irq_masks_cache) > WCD9XXX_NUM_IRQ_REGS) {
+ pr_err("%s: Array Size out of bound\n", __func__);
+ return;
+ }
+
for (i = 0; i < ARRAY_SIZE(wcd9xxx->irq_masks_cur); i++) {
/* If there's been a change in the mask write it back
* to the hardware.
@@ -219,6 +225,7 @@
dev_err(wcd9xxx->dev, "Failed to read interrupt status: %d\n",
ret);
dev_err(wcd9xxx->dev, "Disable irq %d\n", wcd9xxx->irq);
+ disable_irq_wake(wcd9xxx->irq);
disable_irq_nosync(wcd9xxx->irq);
wcd9xxx_unlock_sleep(wcd9xxx);
return IRQ_NONE;
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 3c28447..6ab3a66 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -578,6 +578,17 @@
processing of MPEG transport streams from the main processor.
This can also be compiled as a loadable module.
+config CI_BRIDGE_SPI
+ depends on SPI_QUP
+ tristate "CI Bridge SPI Driver Support"
+ ---help---
+ This driver provides a simple SPI read/write interface to
+ an external CI bridge. It implements a character device
+ driver interface which allows making SPI transactions
+ using the Linux SPI framework.
+
+ To compile this driver as module, choose M here.
+
config HAPTIC_ISA1200
tristate "ISA1200 haptic support"
depends on I2C
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index be3d0a0..e92e119 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -61,6 +61,7 @@
msm_tsif-objs := tsif.o
obj-$(CONFIG_TSIF_CHRDEV) += tsif_chrdev.o
obj-$(CONFIG_TSPP) += tspp.o
+obj-$(CONFIG_CI_BRIDGE_SPI) += ci-bridge-spi.o
obj-$(CONFIG_HAPTIC_ISA1200) += isa1200.o
obj-$(CONFIG_PMIC8058_PWM) += pmic8058-pwm.o
obj-$(CONFIG_PMIC8XXX_VIBRATOR) += pm8xxx-vibrator.o
diff --git a/drivers/misc/ci-bridge-spi.c b/drivers/misc/ci-bridge-spi.c
new file mode 100644
index 0000000..368bef7
--- /dev/null
+++ b/drivers/misc/ci-bridge-spi.c
@@ -0,0 +1,428 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/* This driver implements a simple SPI read/write interface to access
+ * an external device over SPI.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/spi/spi.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include <linux/ci-bridge-spi.h>
+
+#define CI_MAX_BUFFER_SIZE (64 * 1024)
+
+struct ci_bridge {
+ dev_t ci_bridge_dev;
+ struct cdev cdev;
+ struct class *bridge_class;
+ struct device *bridge_dev;
+ char *write_buffer;
+ char *read_buffer;
+ struct mutex lock;
+ struct spi_device *spi;
+ unsigned int gpio_reset_pin;
+ unsigned int gpio_interrupt_pin;
+ int num_opened;
+
+};
+
+static struct ci_bridge ci;
+
+static int __devinit ci_bridge_spi_probe(struct spi_device *spi)
+{
+ int ret;
+ struct ci_bridge_platform_data *pdata;
+
+ if (spi->dev.platform_data == NULL) {
+ pr_err("%s: platform data is missing\n", __func__);
+ return -EINVAL;
+ }
+
+ ci.spi = spi;
+ ci.num_opened = 0;
+ mutex_init(&ci.lock);
+ spi_set_drvdata(spi, &ci);
+ pdata = spi->dev.platform_data;
+ ci.gpio_reset_pin = pdata->reset_pin;
+ ci.gpio_interrupt_pin = pdata->interrupt_pin;
+
+ ret = gpio_request(ci.gpio_reset_pin, "ci_bridge_spi");
+ if (ret) {
+ pr_err("%s: GPIO request for pin number %u failed\n",
+ __func__, ci.gpio_reset_pin);
+ return ret;
+ }
+ ret = gpio_direction_output(ci.gpio_reset_pin, 1);
+ if (ret) {
+ pr_err("%s: unable to set GPIO direction, err=%d\n",
+ __func__, ret);
+ goto err_free_reset_pin;
+ }
+
+ ret = gpio_request(ci.gpio_interrupt_pin, "ci_bridge_spi");
+ if (ret) {
+ pr_err("%s: GPIO request for pin number %u failed\n",
+ __func__, ci.gpio_interrupt_pin);
+ goto err_free_reset_pin;
+ }
+ ret = gpio_direction_input(ci.gpio_interrupt_pin);
+ if (ret) {
+ pr_err("%s: unable to set GPIO direction, err=%d\n",
+ __func__, ret);
+ goto err_free_int_pin;
+ }
+
+ return 0;
+
+err_free_int_pin:
+ gpio_free(ci.gpio_interrupt_pin);
+err_free_reset_pin:
+ gpio_free(ci.gpio_reset_pin);
+
+ return ret;
+}
+
+static int __devexit ci_bridge_spi_remove(struct spi_device *spi)
+{
+ struct ci_bridge *bridge = spi_get_drvdata(spi);
+
+ spi_set_drvdata(bridge->spi, NULL);
+ bridge->spi = NULL;
+ mutex_destroy(&ci.lock);
+
+ gpio_free(ci.gpio_reset_pin);
+ gpio_free(ci.gpio_interrupt_pin);
+
+ return 0;
+}
+
+static struct spi_driver ci_bridge_driver = {
+ .driver = {
+ .name = "ci_bridge_spi",
+ .owner = THIS_MODULE,
+ },
+ .probe = ci_bridge_spi_probe,
+ .remove = __devexit_p(ci_bridge_spi_remove),
+};
+
+static void ci_bridge_spi_completion_cb(void *arg)
+{
+ complete(arg);
+}
+
+static ssize_t ci_bridge_spi_read(struct file *filp,
+ char __user *buf,
+ size_t count,
+ loff_t *f_pos)
+{
+ int ret = 0;
+ unsigned long not_copied = 0;
+ struct spi_transfer spi_transfer;
+ struct spi_message spi_message;
+ DECLARE_COMPLETION_ONSTACK(context);
+ struct ci_bridge *bridge = filp->private_data;
+
+ if ((bridge == NULL) || (bridge->spi == NULL))
+ return -ENODEV;
+
+ if (count > CI_MAX_BUFFER_SIZE)
+ return -EMSGSIZE;
+
+ memset(&spi_transfer, 0, sizeof(struct spi_transfer));
+ memset(&spi_message, 0, sizeof(struct spi_message));
+
+ mutex_lock(&bridge->lock);
+
+ spi_transfer.rx_buf = bridge->read_buffer;
+ spi_transfer.len = count;
+ spi_message_init(&spi_message);
+ spi_message_add_tail(&spi_transfer, &spi_message);
+ spi_message.complete = ci_bridge_spi_completion_cb;
+ spi_message.context = &context;
+
+ /* must use spi_async in a context that may sleep */
+ ret = spi_async(bridge->spi, &spi_message);
+ if (ret == 0) {
+ wait_for_completion(&context);
+
+ if (spi_message.status == 0) {
+ /* spi_message.actual_length should contain the number
+ * of bytes actually read and should update ret to be
+ * the actual length, but since our driver doesn't
+ * support this, assume all count bytes were read.
+ */
+ ret = count;
+ }
+
+ if (ret > 0) {
+ not_copied =
+ copy_to_user(buf, bridge->read_buffer, ret);
+ if (not_copied == ret)
+ ret = -EFAULT;
+ else
+ ret -= not_copied;
+ }
+ } else {
+ pr_err("%s: Error calling spi_async, ret = %d\n",
+ __func__, ret);
+ }
+
+ mutex_unlock(&bridge->lock);
+
+ return ret;
+}
+
+static ssize_t ci_bridge_spi_write(struct file *filp,
+ const char __user *buf,
+ size_t count,
+ loff_t *f_pos)
+{
+ int ret = 0;
+ unsigned long not_copied = 0;
+ struct spi_transfer spi_transfer;
+ struct spi_message spi_message;
+ DECLARE_COMPLETION_ONSTACK(context);
+ struct ci_bridge *bridge = filp->private_data;
+
+ if ((bridge == NULL) || (bridge->spi == NULL))
+ return -ENODEV;
+
+ if (count > CI_MAX_BUFFER_SIZE)
+ return -EMSGSIZE;
+
+ memset(&spi_transfer, 0, sizeof(struct spi_transfer));
+ memset(&spi_message, 0, sizeof(struct spi_message));
+
+ mutex_lock(&bridge->lock);
+ /* copy user data to our SPI Tx buffer */
+ not_copied = copy_from_user(bridge->write_buffer, buf, count);
+ if (not_copied != 0) {
+ ret = -EFAULT;
+ } else {
+ spi_transfer.tx_buf = bridge->write_buffer;
+ spi_transfer.len = count;
+
+ spi_message_init(&spi_message);
+ spi_message_add_tail(&spi_transfer, &spi_message);
+ spi_message.complete = ci_bridge_spi_completion_cb;
+ spi_message.context = &context;
+
+ /* must use spi_async in a context that may sleep */
+ ret = spi_async(bridge->spi, &spi_message);
+ if (ret == 0) {
+ wait_for_completion(&context);
+ /* update ret to contain
+ * the number of bytes actually written
+ */
+ if (spi_message.status == 0)
+ ret = spi_transfer.len;
+ else
+ pr_err("%s: SPI transfer error, spi_message.status = %d\n",
+ __func__, spi_message.status);
+ } else {
+ pr_err("%s: Error calling spi_async, ret = %d\n",
+ __func__, ret);
+ }
+ }
+ mutex_unlock(&bridge->lock);
+
+ return ret;
+}
+
+static int ci_bridge_spi_open(struct inode *inode, struct file *filp)
+{
+ /* forbid opening more then one instance at a time,
+ parallel execution can still be problematic */
+ if (ci.num_opened != 0)
+ return -EBUSY;
+
+ /* allocate write buffer */
+ ci.write_buffer =
+ kzalloc((CI_MAX_BUFFER_SIZE * sizeof(char)), GFP_KERNEL);
+ if (ci.write_buffer == NULL) {
+ pr_err("%s: Error allocating memory for write buffer\n",
+ __func__);
+ return -ENOMEM;
+ }
+ /* allocate read buffer */
+ ci.read_buffer =
+ kzalloc((CI_MAX_BUFFER_SIZE * sizeof(char)), GFP_KERNEL);
+ if (ci.read_buffer == NULL) {
+ pr_err("%s: Error allocating memory for read buffer\n",
+ __func__);
+ kfree(ci.write_buffer);
+ return -ENOMEM;
+ }
+ /* device is non-seekable */
+ nonseekable_open(inode, filp);
+
+ filp->private_data = &ci;
+ ci.num_opened = 1;
+
+ return 0;
+}
+
+static int ci_bridge_ioctl_get_int(void *arg)
+{
+ int state;
+
+ if (arg == NULL)
+ return -EINVAL;
+
+ state = gpio_get_value_cansleep(ci.gpio_interrupt_pin);
+ if (copy_to_user(arg, &state, sizeof(state)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int ci_bridge_ioctl_reset(unsigned long arg)
+{
+ if ((arg != 0) && (arg != 1))
+ return -EINVAL;
+
+ gpio_set_value_cansleep(ci.gpio_reset_pin, arg);
+
+ return 0;
+}
+
+static long ci_bridge_spi_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret;
+
+ switch (cmd) {
+
+ case CI_BRIDGE_IOCTL_RESET:
+ ret = ci_bridge_ioctl_reset(arg);
+ break;
+
+ case CI_BRIDGE_IOCTL_GET_INT_STATE:
+ ret = ci_bridge_ioctl_get_int((void *) arg);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int ci_bridge_spi_release(struct inode *inode, struct file *filp)
+{
+ struct ci_bridge *bridge = filp->private_data;
+
+ if ((bridge == NULL) || (bridge->spi == NULL))
+ return -ENODEV;
+
+ kfree(bridge->write_buffer);
+ kfree(bridge->read_buffer);
+ filp->private_data = NULL;
+ ci.num_opened = 0;
+
+ return 0;
+}
+
+static const struct file_operations ci_bridge_spi_fops = {
+ .owner = THIS_MODULE,
+ .read = ci_bridge_spi_read,
+ .write = ci_bridge_spi_write,
+ .open = ci_bridge_spi_open,
+ .unlocked_ioctl = ci_bridge_spi_ioctl,
+ .release = ci_bridge_spi_release,
+ .llseek = no_llseek,
+};
+
+static int __init ci_bridge_init(void)
+{
+ int ret = 0;
+
+ ret = alloc_chrdev_region(&ci.ci_bridge_dev, 0, 1, "ci_bridge_spi");
+ if (ret != 0)
+ return ret;
+
+ ci.bridge_class = class_create(THIS_MODULE, "ci_bridge_spi");
+ if (IS_ERR(ci.bridge_class)) {
+ ret = PTR_ERR(ci.bridge_class);
+ pr_err("Error creating ci.bridge_class: %d\n", ret);
+ goto free_region;
+ }
+
+ cdev_init(&ci.cdev, &ci_bridge_spi_fops);
+ ci.cdev.owner = THIS_MODULE;
+ ret = cdev_add(&ci.cdev, ci.ci_bridge_dev, 1);
+ if (ret != 0) {
+ pr_err("Error calling cdev_add: %d\n", ret);
+ goto class_destroy;
+ }
+
+
+ ci.bridge_dev = device_create(ci.bridge_class, NULL, ci.cdev.dev,
+ &ci, "ci_bridge_spi0");
+ if (IS_ERR(ci.bridge_dev)) {
+ ret = PTR_ERR(ci.bridge_dev);
+ pr_err("device_create failed: %d\n", ret);
+ goto del_cdev;
+ }
+
+ ret = spi_register_driver(&ci_bridge_driver);
+ if (ret != 0) {
+ pr_err("Error registering spi driver: %d\n", ret);
+ goto device_destroy;
+ }
+
+ /* successful return */
+ return 0;
+
+device_destroy:
+ device_destroy(ci.bridge_class, ci.ci_bridge_dev);
+
+del_cdev:
+ cdev_del(&ci.cdev);
+
+class_destroy:
+ class_destroy(ci.bridge_class);
+
+free_region:
+ unregister_chrdev_region(ci.ci_bridge_dev, 1);
+
+ return ret;
+}
+
+static void __exit ci_bridge_exit(void)
+{
+ spi_unregister_driver(&ci_bridge_driver);
+ device_destroy(ci.bridge_class, ci.ci_bridge_dev);
+ cdev_del(&ci.cdev);
+ class_destroy(ci.bridge_class);
+ unregister_chrdev_region(ci.ci_bridge_dev, 1);
+}
+
+module_init(ci_bridge_init);
+module_exit(ci_bridge_exit);
+
+MODULE_DESCRIPTION("CI Bridge SPI Driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 254672f..91253ff 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1737,6 +1737,7 @@
brq->data.blksz = 512;
brq->data.blocks = mqrq->packed_blocks + 1;
brq->data.flags |= MMC_DATA_WRITE;
+ brq->data.fault_injected = false;
brq->stop.opcode = MMC_STOP_TRANSMISSION;
brq->stop.arg = 0;
diff --git a/drivers/mmc/card/mmc_block_test.c b/drivers/mmc/card/mmc_block_test.c
index 5f5a178..2307d7a 100644
--- a/drivers/mmc/card/mmc_block_test.c
+++ b/drivers/mmc/card/mmc_block_test.c
@@ -152,6 +152,7 @@
BKOPS_MAX_TESTCASE = BKOPS_URGENT_LEVEL_3,
TEST_LONG_SEQUENTIAL_READ,
+ TEST_LONG_SEQUENTIAL_WRITE,
};
enum mmc_block_test_group {
@@ -180,6 +181,7 @@
struct dentry *discard_sanitize_test;
struct dentry *bkops_test;
struct dentry *long_sequential_read_test;
+ struct dentry *long_sequential_write_test;
};
struct mmc_block_test_data {
@@ -590,6 +592,8 @@
return "\nTest urgent BKOPS level 3";
case TEST_LONG_SEQUENTIAL_READ:
return "Test long sequential read";
+ case TEST_LONG_SEQUENTIAL_WRITE:
+ return "Test long sequential write";
default:
return "Unknown testcase";
}
@@ -1289,9 +1293,12 @@
return -EINVAL;
}
- test_direction = READ;
+ if (td->test_info.testcase == TEST_LONG_SEQUENTIAL_WRITE)
+ test_direction = WRITE;
+ else
+ test_direction = READ;
- test_pr_info("%s: Adding %d read requests, first req_id=%d", __func__,
+ test_pr_info("%s: Adding %d write requests, first req_id=%d", __func__,
LONG_TEST_ACTUAL_NUM_REQS, td->wr_rd_next_req_id);
for (j = 0; j < LONG_TEST_ACTUAL_NUM_REQS; j++) {
@@ -1421,6 +1428,9 @@
ret = prepare_packed_control_tests_requests(td, 0,
test_packed_trigger, is_random);
break;
+ case TEST_LONG_SEQUENTIAL_WRITE:
+ ret = prepare_long_test_requests(td);
+ break;
case TEST_LONG_SEQUENTIAL_READ:
ret = prepare_long_test_requests(td);
break;
@@ -2592,6 +2602,96 @@
.read = long_sequential_read_test_read,
};
+static ssize_t long_sequential_write_test_write(struct file *file,
+ const char __user *buf,
+ size_t count,
+ loff_t *ppos)
+{
+ int ret = 0;
+ int i = 0;
+ int number = -1;
+ unsigned int mtime, integer, fraction;
+
+ test_pr_info("%s: -- Long Sequential Write TEST --", __func__);
+
+ sscanf(buf, "%d", &number);
+
+ if (number <= 0)
+ number = 1;
+
+ memset(&mbtd->test_info, 0, sizeof(struct test_info));
+ mbtd->test_group = TEST_GENERAL_GROUP;
+
+ mbtd->test_info.data = mbtd;
+ mbtd->test_info.prepare_test_fn = prepare_test;
+ mbtd->test_info.get_test_case_str_fn = get_test_case_str;
+
+ for (i = 0 ; i < number ; ++i) {
+ test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
+ test_pr_info("%s: ====================", __func__);
+
+ mbtd->test_info.testcase = TEST_LONG_SEQUENTIAL_WRITE;
+ mbtd->is_random = NON_RANDOM_TEST;
+ ret = test_iosched_start_test(&mbtd->test_info);
+ if (ret)
+ break;
+
+ mtime = jiffies_to_msecs(mbtd->test_info.test_duration);
+
+ test_pr_info("%s: time is %u msec, size is %u.%u MiB",
+ __func__, mtime, LONG_TEST_SIZE_INTEGER,
+ LONG_TEST_SIZE_FRACTION);
+
+ /* we first multiply in order not to lose precision */
+ mtime *= MB_MSEC_RATIO_APPROXIMATION;
+ /* divide values to get a MiB/sec integer value with one
+ digit of precision
+ */
+ fraction = integer = (LONG_TEST_ACTUAL_BYTE_NUM * 10) / mtime;
+ integer /= 10;
+ /* and calculate the MiB value fraction */
+ fraction -= integer * 10;
+
+ test_pr_info("%s: Throughput: %u.%u MiB/sec\n",
+ __func__, integer, fraction);
+
+ /* Allow FS requests to be dispatched */
+ msleep(1000);
+ }
+
+ return count;
+}
+
+static ssize_t long_sequential_write_test_read(struct file *file,
+ char __user *buffer,
+ size_t count,
+ loff_t *offset)
+{
+ memset((void *)buffer, 0, count);
+
+ snprintf(buffer, count,
+ "\nlong_sequential_write_test\n"
+ "=========\n"
+ "Description:\n"
+ "This test runs the following scenarios\n"
+ "- Long Sequential Write Test: this test measures write "
+ "throughput at the driver level by sequentially writing many "
+ "large requests\n");
+
+ if (message_repeat == 1) {
+ message_repeat = 0;
+ return strnlen(buffer, count);
+ } else
+ return 0;
+}
+
+const struct file_operations long_sequential_write_test_ops = {
+ .open = test_open,
+ .write = long_sequential_write_test_write,
+ .read = long_sequential_write_test_read,
+};
+
+
static void mmc_block_test_debugfs_cleanup(void)
{
debugfs_remove(mbtd->debug.random_test_seed);
@@ -2602,6 +2702,7 @@
debugfs_remove(mbtd->debug.discard_sanitize_test);
debugfs_remove(mbtd->debug.bkops_test);
debugfs_remove(mbtd->debug.long_sequential_read_test);
+ debugfs_remove(mbtd->debug.long_sequential_write_test);
}
static int mmc_block_test_debugfs_init(void)
@@ -2694,6 +2795,16 @@
if (!mbtd->debug.long_sequential_read_test)
goto err_nomem;
+ mbtd->debug.long_sequential_write_test = debugfs_create_file(
+ "long_sequential_write_test",
+ S_IRUGO | S_IWUGO,
+ tests_root,
+ NULL,
+ &long_sequential_write_test_ops);
+
+ if (!mbtd->debug.long_sequential_write_test)
+ goto err_nomem;
+
return 0;
err_nomem:
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index cc91646..8897f18a 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -201,11 +201,12 @@
if (!mq->queue)
return -ENOMEM;
+ memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur));
+ memset(&mq->mqrq_prev, 0, sizeof(mq->mqrq_prev));
+
INIT_LIST_HEAD(&mqrq_cur->packed_list);
INIT_LIST_HEAD(&mqrq_prev->packed_list);
- memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur));
- memset(&mq->mqrq_prev, 0, sizeof(mq->mqrq_prev));
mq->mqrq_cur = mqrq_cur;
mq->mqrq_prev = mqrq_prev;
mq->queue->queuedata = mq;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 3aa38d2..48516b6 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2639,7 +2639,9 @@
mmc_card_is_removable(host))
return err;
- mmc_claim_host(host);
+ if (!mmc_try_claim_host(host))
+ return -EBUSY;
+
if (card && mmc_card_mmc(card) &&
(card->ext_csd.cache_size > 0)) {
enable = !!enable;
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 2fbd804..49bbe09 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -213,9 +213,9 @@
#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
/**
- * Apply soft reset to all SDCC BAM pipes
+ * Apply reset
*
- * This function applies soft reset to SDCC BAM pipe.
+ * This function resets SPS BAM and DML cores.
*
* This function should be called to recover from error
* conditions encountered during CMD/DATA tranfsers with card.
@@ -223,43 +223,64 @@
* @host - Pointer to driver's host structure
*
*/
-static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
+static int msmsdcc_bam_dml_reset_and_restore(struct msmsdcc_host *host)
{
int rc;
+ /* Reset and init DML */
+ rc = msmsdcc_dml_init(host);
+ if (rc) {
+ pr_err("%s: msmsdcc_dml_init error=%d\n",
+ mmc_hostname(host->mmc), rc);
+ goto out;
+ }
+
/* Reset all SDCC BAM pipes */
rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
- if (rc)
- pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
+ if (rc) {
+ pr_err("%s: msmsdcc_sps_reset_ep(prod) error=%d\n",
mmc_hostname(host->mmc), rc);
- rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
- if (rc)
- pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
- mmc_hostname(host->mmc), rc);
+ goto out;
+ }
- if (host->sps.reset_device) {
- rc = sps_device_reset(host->sps.bam_handle);
- if (rc)
- pr_err("%s: sps_device_reset error=%d\n",
+ rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
+ if (rc) {
+ pr_err("%s: msmsdcc_sps_reset_ep(cons) error=%d\n",
mmc_hostname(host->mmc), rc);
- host->sps.reset_device = false;
+ goto out;
+ }
+
+ /* Reset BAM */
+ rc = sps_device_reset(host->sps.bam_handle);
+ if (rc) {
+ pr_err("%s: sps_device_reset error=%d\n",
+ mmc_hostname(host->mmc), rc);
+ goto out;
}
/* Restore all BAM pipes connections */
rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
- if (rc)
- pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
+ if (rc) {
+ pr_err("%s: msmsdcc_sps_restore_ep(prod) error=%d\n",
mmc_hostname(host->mmc), rc);
+ goto out;
+ }
+
rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
if (rc)
- pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
+ pr_err("%s: msmsdcc_sps_restore_ep(cons) error=%d\n",
mmc_hostname(host->mmc), rc);
+ else
+ host->sps.reset_bam = false;
+
+out:
+ return rc;
}
/**
* Apply soft reset
*
- * This function applies soft reset to SDCC core and DML core.
+ * This function applies soft reset to SDCC core.
*
* This function should be called to recover from error
* conditions encountered with CMD/DATA tranfsers with card.
@@ -277,6 +298,11 @@
*/
if (is_sw_reset_save_config(host)) {
ktime_t start;
+ uint32_t dll_config = 0;
+
+
+ if (is_sw_reset_save_config_broken(host))
+ dll_config = readl_relaxed(host->base + MCI_DLL_CONFIG);
writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
| MCI_SW_RST_CFG, host->base + MMCIPOWER);
@@ -296,6 +322,11 @@
BUG();
}
}
+
+ if (is_sw_reset_save_config_broken(host)) {
+ writel_relaxed(dll_config, host->base + MCI_DLL_CONFIG);
+ mb();
+ }
} else {
writel_relaxed(0, host->base + MMCICOMMAND);
msmsdcc_sync_reg_wr(host);
@@ -354,25 +385,25 @@
static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
{
if (is_soft_reset(host)) {
- if (is_sps_mode(host)) {
- /* Reset DML first */
- msmsdcc_dml_reset(host);
+ if (is_sps_mode(host))
/*
- * delay the SPS pipe reset in thread context as
+ * delay the SPS BAM reset in thread context as
* sps_connect/sps_disconnect APIs can be called
* only from non-atomic context.
*/
- host->sps.pipe_reset_pending = true;
- }
- mb();
+ host->sps.reset_bam = true;
+
msmsdcc_soft_reset(host);
pr_debug("%s: Applied soft reset to Controller\n",
mmc_hostname(host->mmc));
-
- if (is_sps_mode(host))
- msmsdcc_dml_init(host);
} else {
+ /*
+ * When there is a requirement to use this hard reset,
+ * BAM needs to be reconfigured as well by calling
+ * msmsdcc_sps_exit and msmsdcc_sps_init.
+ */
+
/* Give Clock reset (hard reset) to controller */
u32 mci_clk = 0;
u32 mci_mask0 = 0;
@@ -2086,6 +2117,7 @@
{
struct msmsdcc_host *host = mmc_priv(mmc);
unsigned long flags;
+ int retries = 5;
/*
* Get the SDIO AL client out of LPM.
@@ -2094,10 +2126,14 @@
if (host->plat->is_sdio_al_client)
msmsdcc_sdio_al_lpm(mmc, false);
- /* check if sps pipe reset is pending? */
- if (is_sps_mode(host) && host->sps.pipe_reset_pending) {
- msmsdcc_sps_pipes_reset_and_restore(host);
- host->sps.pipe_reset_pending = false;
+ /* check if sps bam needs to be reset */
+ if (is_sps_mode(host) && host->sps.reset_bam) {
+ while (retries) {
+ if (!msmsdcc_bam_dml_reset_and_restore(host))
+ break;
+ pr_err("%s: msmsdcc_bam_dml_reset_and_restore returned error. %d attempts left.\n",
+ mmc_hostname(host->mmc), --retries);
+ }
}
spin_lock_irqsave(&host->lock, flags);
@@ -2118,8 +2154,9 @@
/*
* Don't start the request if SDCC is not in proper state to handle it
*/
- if (!host->pwr || !atomic_read(&host->clks_on)
- || host->sdcc_irq_disabled) {
+ if (!host->pwr || !atomic_read(&host->clks_on) ||
+ host->sdcc_irq_disabled ||
+ host->sps.reset_bam) {
WARN(1, "%s: %s: SDCC is in bad state. don't process"
" new request (CMD%d)\n", mmc_hostname(host->mmc),
__func__, mrq->cmd->opcode);
@@ -3197,8 +3234,21 @@
/*
* For DDR50 mode, controller needs clock rate to be
* double than what is required on the SD card CLK pin.
+ *
+ * Setting DDR timing mode in controller before setting the
+ * clock rate will make sure that card don't see the double
+ * clock rate even for very small duration. Some eMMC
+ * cards seems to lock up if they see clock frequency > 52MHz.
*/
if (ios->timing == MMC_TIMING_UHS_DDR50) {
+ u32 clk;
+
+ clk = readl_relaxed(host->base + MMCICLOCK);
+ clk &= ~(0x7 << 14); /* clear SELECT_IN field */
+ clk |= (3 << 14); /* set DDR timing mode */
+ writel_relaxed(clk, host->base + MMCICLOCK);
+ msmsdcc_sync_reg_wr(host);
+
/*
* Make sure that we don't double the clock if
* doubled clock rate is already set
@@ -4586,11 +4636,8 @@
BUG_ON(!is_sps_mode(host));
if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
- /**
- * Reset the all endpoints along with reseting the sps device.
- */
- host->sps.pipe_reset_pending = true;
- host->sps.reset_device = true;
+ /* Reset all endpoints along with resetting bam. */
+ host->sps.reset_bam = true;
pr_err("%s: BAM Global ERROR IRQ happened\n",
mmc_hostname(host->mmc));
@@ -5006,6 +5053,10 @@
host->curr.data_xfered, host->curr.xfer_remain);
}
+ if (host->sps.reset_bam)
+ pr_err("%s: SPS BAM reset failed: sps reset_bam=%d\n",
+ mmc_hostname(host->mmc), host->sps.reset_bam);
+
pr_err("%s: got_dataend=%d, prog_enable=%d,"
" wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
" req_tout_ms=%d\n", mmc_hostname(host->mmc),
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index c66d1a5..af5498e 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -2,7 +2,7 @@
* linux/drivers/mmc/host/msmsdcc.h - QCT MSM7K SDC Controller
*
* Copyright (C) 2008 Google, All Rights Reserved.
- * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -321,8 +321,7 @@
unsigned int dest_pipe_index;
unsigned int busy;
unsigned int xfer_req_cnt;
- bool pipe_reset_pending;
- bool reset_device;
+ bool reset_bam;
struct tasklet_struct tlet;
};
@@ -446,6 +445,7 @@
#define MSMSDCC_IO_PAD_PWR_SWITCH (1 << 8)
#define MSMSDCC_AUTO_CMD19 (1 << 9)
#define MSMSDCC_AUTO_CMD21 (1 << 10)
+#define MSMSDCC_SW_RST_CFG_BROKEN (1 << 11)
#define set_hw_caps(h, val) ((h)->hw_caps |= val)
#define is_sps_mode(h) ((h)->hw_caps & MSMSDCC_SPS_BAM_SUP)
@@ -459,6 +459,8 @@
#define is_io_pad_pwr_switch(h) ((h)->hw_caps & MSMSDCC_IO_PAD_PWR_SWITCH)
#define is_auto_cmd19(h) ((h)->hw_caps & MSMSDCC_AUTO_CMD19)
#define is_auto_cmd21(h) ((h)->hw_caps & MSMSDCC_AUTO_CMD21)
+#define is_sw_reset_save_config_broken(h) \
+ ((h)->hw_caps & MSMSDCC_SW_RST_CFG_BROKEN)
/* Set controller capabilities based on version */
static inline void set_default_hw_caps(struct msmsdcc_host *host)
@@ -490,7 +492,11 @@
host->hw_caps |= MSMSDCC_AUTO_CMD21;
if (step >= 0x2b) /* SDCC v4 2.1.0 and greater */
- host->hw_caps |= MSMSDCC_SW_RST | MSMSDCC_AUTO_CMD21;
+ host->hw_caps |= MSMSDCC_SW_RST | MSMSDCC_SW_RST_CFG |
+ MSMSDCC_AUTO_CMD21;
+
+ if (step == 0x2b)
+ host->hw_caps |= MSMSDCC_SW_RST_CFG_BROKEN;
}
int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave);
diff --git a/drivers/net/ethernet/msm/msm_rmnet_smux.c b/drivers/net/ethernet/msm/msm_rmnet_smux.c
index 5f29406..e56a64e 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_smux.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_smux.c
@@ -482,7 +482,7 @@
p = netdev_priv(priv);
DBG0("[%s] Low WM hit dev:%s\n", __func__, dev->name);
spin_lock_irqsave(&p->tx_queue_lock, flags);
- netif_start_queue(dev);
+ netif_wake_queue(dev);
spin_unlock_irqrestore(&p->tx_queue_lock, flags);
break;
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 376750f..7b7e05e 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -343,6 +343,18 @@
SMB349 be operated as a slave device via the power supply
framework.
+config SMB350_CHARGER
+ tristate "smb350 charger"
+ depends on I2C
+ help
+ Say Y to enable battery charging by SMB350 switching mode based
+ external charger. The device supports stack-cell battery charging.
+ The driver configures the device volatile parameters
+ and the charger device works autonomously.
+ The driver supports charger-enable and charger-suspend/resume.
+ The driver reports the charger status via the power supply framework.
+ A charger status change triggers an IRQ via the device STAT pin.
+
config BATTERY_MSM_FAKE
tristate "Fake MSM battery"
depends on ARCH_MSM && BATTERY_MSM
@@ -388,6 +400,18 @@
help
Say Y here to enable Test sysfs Interface for BQ27520 Drivers.
+config BATTERY_BQ28400
+ tristate "BQ28400 battery driver"
+ depends on I2C
+ default n
+ help
+ Say Y here to enable support for batteries with BQ28400 (I2C) chips.
+ The bq28400 Texas Instruments Inc device monitors the battery
+ charging/discharging status via Rsens resistor, typically 10 mohm.
+ It monitors the battery temperature via Thermistor.
+ The device monitors the battery level (Relative-State-Of-Charge).
+ The device is SBS compliant, providing battery info over I2C.
+
config PM8921_CHARGER
tristate "PM8921 Charger driver"
depends on MFD_PM8921_CORE
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 3521cfd..3e74f35 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -48,10 +48,12 @@
obj-$(CONFIG_PM8058_CHARGER) += pmic8058-charger.o
obj-$(CONFIG_ISL9519_CHARGER) += isl9519q.o
obj-$(CONFIG_SMB349_CHARGER) += smb349.o
+obj-$(CONFIG_SMB350_CHARGER) += smb350_charger.o
obj-$(CONFIG_PM8058_FIX_USB) += pm8058_usb_fix.o
obj-$(CONFIG_BATTERY_QCIBAT) += qci_battery.o
obj-$(CONFIG_BATTERY_BQ27520) += bq27520_fuelgauger.o
obj-$(CONFIG_BATTERY_BQ27541) += bq27541_fuelgauger.o
+obj-$(CONFIG_BATTERY_BQ28400) += bq28400_battery.o
obj-$(CONFIG_SMB137B_CHARGER) += smb137b.o
obj-$(CONFIG_PM8XXX_CCADC) += pm8xxx-ccadc.o
obj-$(CONFIG_PM8921_BMS) += pm8921-bms.o
diff --git a/drivers/power/bq28400_battery.c b/drivers/power/bq28400_battery.c
new file mode 100644
index 0000000..39d52cb
--- /dev/null
+++ b/drivers/power/bq28400_battery.c
@@ -0,0 +1,917 @@
+/* Copyright (c) 2012 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/*
+ * High Level description:
+ * http://www.ti.com/lit/ds/symlink/bq28400.pdf
+ * Thechnical Reference:
+ * http://www.ti.com/lit/ug/sluu431/sluu431.pdf
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/power_supply.h>
+#include <linux/bitops.h>
+#include <linux/regulator/consumer.h>
+#include <linux/printk.h>
+
+#define BQ28400_NAME "bq28400"
+#define BQ28400_REV "1.0"
+
+/* SBS Commands (page 63) */
+
+#define SBS_MANUFACTURER_ACCESS 0x00
+#define SBS_BATTERY_MODE 0x03
+#define SBS_TEMPERATURE 0x08
+#define SBS_VOLTAGE 0x09
+#define SBS_CURRENT 0x0A
+#define SBS_AVG_CURRENT 0x0B
+#define SBS_MAX_ERROR 0x0C
+#define SBS_RSOC 0x0D /* Relative State Of Charge */
+#define SBS_REMAIN_CAPACITY 0x0F
+#define SBS_FULL_CAPACITY 0x10
+#define SBS_CHG_CURRENT 0x14
+#define SBS_CHG_VOLTAGE 0x15
+#define SBS_BATTERY_STATUS 0x16
+#define SBS_CYCLE_COUNT 0x17
+#define SBS_DESIGN_CAPACITY 0x18
+#define SBS_DESIGN_VOLTAGE 0x19
+#define SBS_SPEC_INFO 0x1A
+#define SBS_MANUFACTURE_DATE 0x1B
+#define SBS_SERIAL_NUMBER 0x1C
+#define SBS_MANUFACTURER_NAME 0x20
+#define SBS_DEVICE_NAME 0x21
+#define SBS_DEVICE_CHEMISTRY 0x22
+#define SBS_MANUFACTURER_DATA 0x23
+#define SBS_AUTHENTICATE 0x2F
+#define SBS_CELL_VOLTAGE1 0x3E
+#define SBS_CELL_VOLTAGE2 0x3F
+
+/* Extended SBS Commands (page 71) */
+
+#define SBS_FET_CONTROL 0x46
+#define SBS_SAFETY_ALERT 0x50
+#define SBS_SAFETY_STATUS 0x51
+#define SBS_PE_ALERT 0x52
+#define SBS_PE_STATUS 0x53
+#define SBS_OPERATION_STATUS 0x54
+#define SBS_CHARGING_STATUS 0x55
+#define SBS_FET_STATUS 0x56
+#define SBS_PACK_VOLTAGE 0x5A
+#define SBS_TS0_TEMPERATURE 0x5E
+#define SBS_FULL_ACCESS_KEY 0x61
+#define SBS_PF_KEY 0x62
+#define SBS_AUTH_KEY3 0x63
+#define SBS_AUTH_KEY2 0x64
+#define SBS_AUTH_KEY1 0x65
+#define SBS_AUTH_KEY0 0x66
+#define SBS_MANUFACTURER_INFO 0x70
+#define SBS_SENSE_RESISTOR 0x71
+#define SBS_TEMP_RANGE 0x72
+
+/* SBS Sub-Commands (16 bits) */
+/* SBS_MANUFACTURER_ACCESS CMD */
+#define SUBCMD_DEVICE_TYPE 0x01
+#define SUBCMD_FIRMWARE_VERSION 0x02
+#define SUBCMD_HARDWARE_VERSION 0x03
+#define SUBCMD_DF_CHECKSUM 0x04
+#define SUBCMD_EDV 0x05
+#define SUBCMD_CHEMISTRY_ID 0x08
+
+/* SBS_CHARGING_STATUS */
+#define CHG_STATUS_BATTERY_DEPLETED BIT(0)
+#define CHG_STATUS_OVERCHARGE BIT(1)
+#define CHG_STATUS_OVERCHARGE_CURRENT BIT(2)
+#define CHG_STATUS_OVERCHARGE_VOLTAGE BIT(3)
+#define CHG_STATUS_CELL_BALANCING BIT(6)
+#define CHG_STATUS_HOT_TEMP_CHARGING BIT(8)
+#define CHG_STATUS_STD1_TEMP_CHARGING BIT(9)
+#define CHG_STATUS_STD2_TEMP_CHARGING BIT(10)
+#define CHG_STATUS_LOW_TEMP_CHARGING BIT(11)
+#define CHG_STATUS_PRECHARGING_EXIT BIT(13)
+#define CHG_STATUS_SUSPENDED BIT(14)
+#define CHG_STATUS_DISABLED BIT(15)
+
+/* SBS_FET_STATUS */
+#define FET_STATUS_DISCHARGE BIT(1)
+#define FET_STATUS_CHARGE BIT(2)
+#define FET_STATUS_PRECHARGE BIT(3)
+
+/* SBS_BATTERY_STATUS */
+#define BAT_STATUS_SBS_ERROR 0x0F
+#define BAT_STATUS_EMPTY BIT(4)
+#define BAT_STATUS_FULL BIT(5)
+#define BAT_STATUS_DISCHARGING BIT(6)
+#define BAT_STATUS_OVER_TEMPERATURE BIT(12)
+#define BAT_STATUS_OVER_CHARGED BIT(15)
+
+#define ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN (-2731)
+#define BQ_TERMINATION_CURRENT_MA 200
+
+#define BQ_MAX_STR_LEN 32
+
+struct bq28400_device {
+ struct i2c_client *client;
+ struct delayed_work periodic_user_space_update_work;
+ struct dentry *dent;
+ struct power_supply batt_psy;
+ struct power_supply *dc_psy;
+ bool is_charging_enabled;
+};
+
+static struct bq28400_device *bq28400_dev;
+
+static enum power_supply_property pm_power_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CURRENT_AVG,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_CHARGE_FULL,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+struct debug_reg {
+ char *name;
+ u8 reg;
+ u16 subcmd;
+};
+
+#define BQ28400_DEBUG_REG(x) {#x, SBS_##x, 0}
+#define BQ28400_DEBUG_SUBREG(x, y) {#y, SBS_##x, SUBCMD_##y}
+
+/* Note: Some register can be read only in Unsealed mode */
+static struct debug_reg bq28400_debug_regs[] = {
+ BQ28400_DEBUG_REG(MANUFACTURER_ACCESS),
+ BQ28400_DEBUG_REG(BATTERY_MODE),
+ BQ28400_DEBUG_REG(TEMPERATURE),
+ BQ28400_DEBUG_REG(VOLTAGE),
+ BQ28400_DEBUG_REG(CURRENT),
+ BQ28400_DEBUG_REG(AVG_CURRENT),
+ BQ28400_DEBUG_REG(MAX_ERROR),
+ BQ28400_DEBUG_REG(RSOC),
+ BQ28400_DEBUG_REG(REMAIN_CAPACITY),
+ BQ28400_DEBUG_REG(FULL_CAPACITY),
+ BQ28400_DEBUG_REG(CHG_CURRENT),
+ BQ28400_DEBUG_REG(CHG_VOLTAGE),
+ BQ28400_DEBUG_REG(BATTERY_STATUS),
+ BQ28400_DEBUG_REG(CYCLE_COUNT),
+ BQ28400_DEBUG_REG(DESIGN_CAPACITY),
+ BQ28400_DEBUG_REG(DESIGN_VOLTAGE),
+ BQ28400_DEBUG_REG(SPEC_INFO),
+ BQ28400_DEBUG_REG(MANUFACTURE_DATE),
+ BQ28400_DEBUG_REG(SERIAL_NUMBER),
+ BQ28400_DEBUG_REG(MANUFACTURER_NAME),
+ BQ28400_DEBUG_REG(DEVICE_NAME),
+ BQ28400_DEBUG_REG(DEVICE_CHEMISTRY),
+ BQ28400_DEBUG_REG(MANUFACTURER_DATA),
+ BQ28400_DEBUG_REG(AUTHENTICATE),
+ BQ28400_DEBUG_REG(CELL_VOLTAGE1),
+ BQ28400_DEBUG_REG(CELL_VOLTAGE2),
+ BQ28400_DEBUG_REG(SAFETY_ALERT),
+ BQ28400_DEBUG_REG(SAFETY_STATUS),
+ BQ28400_DEBUG_REG(PE_ALERT),
+ BQ28400_DEBUG_REG(PE_STATUS),
+ BQ28400_DEBUG_REG(OPERATION_STATUS),
+ BQ28400_DEBUG_REG(CHARGING_STATUS),
+ BQ28400_DEBUG_REG(FET_STATUS),
+ BQ28400_DEBUG_REG(FULL_ACCESS_KEY),
+ BQ28400_DEBUG_REG(PF_KEY),
+ BQ28400_DEBUG_REG(MANUFACTURER_INFO),
+ BQ28400_DEBUG_REG(SENSE_RESISTOR),
+ BQ28400_DEBUG_REG(TEMP_RANGE),
+ BQ28400_DEBUG_SUBREG(MANUFACTURER_ACCESS, DEVICE_TYPE),
+ BQ28400_DEBUG_SUBREG(MANUFACTURER_ACCESS, FIRMWARE_VERSION),
+ BQ28400_DEBUG_SUBREG(MANUFACTURER_ACCESS, HARDWARE_VERSION),
+ BQ28400_DEBUG_SUBREG(MANUFACTURER_ACCESS, DF_CHECKSUM),
+ BQ28400_DEBUG_SUBREG(MANUFACTURER_ACCESS, EDV),
+ BQ28400_DEBUG_SUBREG(MANUFACTURER_ACCESS, CHEMISTRY_ID),
+};
+
+static int bq28400_read_reg(struct i2c_client *client, u8 reg)
+{
+ int val;
+
+ val = i2c_smbus_read_word_data(client, reg);
+ if (val < 0)
+ pr_err("i2c read fail. reg = 0x%x.ret = %d.\n", reg, val);
+ else
+ pr_debug("reg = 0x%02X.val = 0x%04X.\n", reg , val);
+
+ return val;
+}
+
+static int bq28400_write_reg(struct i2c_client *client, u8 reg, u16 val)
+{
+ int ret;
+
+ ret = i2c_smbus_write_word_data(client, reg, val);
+ if (ret < 0)
+ pr_err("i2c read fail. reg = 0x%x.val = 0x%x.ret = %d.\n",
+ reg, val, ret);
+ else
+ pr_debug("reg = 0x%02X.val = 0x%02X.\n", reg , val);
+
+ return ret;
+}
+
+static int bq28400_read_subcmd(struct i2c_client *client, u8 reg, u16 subcmd)
+{
+ int ret;
+ u8 buf[4];
+ u16 val = 0;
+
+ buf[0] = reg;
+ buf[1] = subcmd & 0xFF;
+ buf[2] = (subcmd >> 8) & 0xFF;
+
+ /* Control sub-command */
+ ret = i2c_master_send(client, buf, 3);
+ if (ret < 0) {
+ pr_err("i2c tx fail. reg = 0x%x.ret = %d.\n", reg, ret);
+ return ret;
+ }
+ udelay(66);
+
+ /* Read Result of subcmd */
+ ret = i2c_master_send(client, buf, 1);
+ memset(buf, 0xAA, sizeof(buf));
+ ret = i2c_master_recv(client, buf, 2);
+ if (ret < 0) {
+ pr_err("i2c rx fail. reg = 0x%x.ret = %d.\n", reg, ret);
+ return ret;
+ }
+ val = (buf[1] << 8) + buf[0];
+
+ pr_debug("reg = 0x%02X.subcmd = 0x%x.val = 0x%04X.\n",
+ reg , subcmd, val);
+
+ return val;
+}
+
+static int bq28400_read_block(struct i2c_client *client, u8 reg,
+ u8 len, u8 *buf)
+{
+ int ret;
+ u32 val;
+
+ ret = i2c_smbus_read_i2c_block_data(client, reg, len, buf);
+ val = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24);
+
+ if (ret < 0)
+ pr_err("i2c read fail. reg = 0x%x.ret = %d.\n", reg, ret);
+ else
+ pr_debug("reg = 0x%02X.val = 0x%04X.\n", reg , val);
+
+ return val;
+}
+
+/*
+ * Read a string from a device.
+ * Returns string length on success or error on failure (negative value).
+ */
+static int bq28400_read_string(struct i2c_client *client, u8 reg, char *str,
+ u8 max_len)
+{
+ int ret;
+ int len;
+
+ ret = bq28400_read_block(client, reg, max_len, str);
+ if (ret < 0)
+ return ret;
+
+ len = str[0]; /* Actual length */
+ if (len > max_len - 2) { /* reduce len byte and null */
+ pr_err("len = %d invalid.\n", len);
+ return -EINVAL;
+ }
+
+ memcpy(&str[0], &str[1], len); /* Move sting to the start */
+ str[len] = 0; /* put NULL after actual size */
+
+ pr_debug("len = %d.str = %s.\n", len, str);
+
+ return len;
+}
+
+#define BQ28400_INVALID_TEMPERATURE -999
+/*
+ * Return the battery temperature in tenths of degree Celsius
+ * Or -99.9 C if something fails.
+ */
+static int bq28400_read_temperature(struct i2c_client *client)
+{
+ int temp;
+
+ /* temperature resolution 0.1 Kelvin */
+ temp = bq28400_read_reg(client, SBS_TEMPERATURE);
+ if (temp < 0)
+ return BQ28400_INVALID_TEMPERATURE;
+
+ temp = temp + ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN;
+
+ pr_debug("temp = %d C\n", temp/10);
+
+ return temp;
+}
+
+/*
+ * Return the battery Voltage in milivolts 0..20 V
+ * Or < 0 if something fails.
+ */
+static int bq28400_read_voltage(struct i2c_client *client)
+{
+ int mvolt = 0;
+
+ mvolt = bq28400_read_reg(client, SBS_VOLTAGE);
+ if (mvolt < 0)
+ return mvolt;
+
+ pr_debug("volt = %d mV.\n", mvolt);
+
+ return mvolt;
+}
+
+/*
+ * Return the battery Current in miliamps
+ * Or 0 if something fails.
+ * Positive current indicates charging
+ * Negative current indicates discharging.
+ * Current-now is calculated every second.
+ */
+static int bq28400_read_current(struct i2c_client *client)
+{
+ s16 current_ma = 0;
+
+ current_ma = bq28400_read_reg(client, SBS_CURRENT);
+
+ pr_debug("current = %d mA.\n", current_ma);
+
+ return current_ma;
+}
+
+/*
+ * Return the Average battery Current in miliamps
+ * Or 0 if something fails.
+ * Positive current indicates charging
+ * Negative current indicates discharging.
+ * Average Current is the rolling 1 minute average current.
+ */
+static int bq28400_read_avg_current(struct i2c_client *client)
+{
+ s16 current_ma = 0;
+
+ current_ma = bq28400_read_reg(client, SBS_AVG_CURRENT);
+
+ pr_debug("avg_current=%d mA.\n", current_ma);
+
+ return current_ma;
+}
+
+/*
+ * Return the battery Relative-State-Of-Charge 0..100 %
+ * Or 0 if something fails.
+ */
+static int bq28400_read_rsoc(struct i2c_client *client)
+{
+ int percentage = 0;
+
+ /* This register is only 1 byte */
+ percentage = i2c_smbus_read_byte_data(client, SBS_RSOC);
+
+ if (percentage < 0)
+ return 0;
+
+ pr_debug("percentage = %d.\n", percentage);
+
+ return percentage;
+}
+
+/*
+ * Return the battery Capacity in mAh.
+ * Or 0 if something fails.
+ */
+static int bq28400_read_full_capacity(struct i2c_client *client)
+{
+ int capacity = 0;
+
+ capacity = bq28400_read_reg(client, SBS_FULL_CAPACITY);
+ if (capacity < 0)
+ return 0;
+
+ pr_debug("full-capacity = %d mAh.\n", capacity);
+
+ return capacity;
+}
+
+/*
+ * Return the battery Capacity in mAh.
+ * Or 0 if something fails.
+ */
+static int bq28400_read_remain_capacity(struct i2c_client *client)
+{
+ int capacity = 0;
+
+ capacity = bq28400_read_reg(client, SBS_REMAIN_CAPACITY);
+ if (capacity < 0)
+ return 0;
+
+ pr_debug("remain-capacity = %d mAh.\n", capacity);
+
+ return capacity;
+}
+
+static int bq28400_enable_charging(struct bq28400_device *bq28400_dev,
+ bool enable)
+{
+ int ret;
+ static bool is_charging_enabled;
+
+ if (bq28400_dev->dc_psy == NULL) {
+ bq28400_dev->dc_psy = power_supply_get_by_name("dc");
+ if (bq28400_dev->dc_psy == NULL) {
+ pr_err("fail to get dc-psy.\n");
+ return -ENODEV;
+ }
+ }
+
+ if (is_charging_enabled == enable) {
+ pr_debug("Charging enable already = %d.\n", enable);
+ return 0;
+ }
+
+ ret = power_supply_set_online(bq28400_dev->dc_psy, enable);
+ if (ret < 0) {
+ pr_err("fail to set dc-psy online to %d.\n", enable);
+ return ret;
+ }
+
+ is_charging_enabled = enable;
+
+ pr_debug("Charging enable = %d.\n", enable);
+
+ return 0;
+}
+
+static int bq28400_get_prop_status(struct i2c_client *client)
+{
+ int status = POWER_SUPPLY_STATUS_UNKNOWN;
+ int rsoc;
+ s16 current_ma = 0;
+ u16 battery_status;
+
+ battery_status = bq28400_read_reg(client, SBS_BATTERY_STATUS);
+
+ if (battery_status & BAT_STATUS_EMPTY)
+ pr_debug("Battery report Empty.\n");
+
+ /* Battery may report FULL before rsoc is 100%
+ * for protection and cell-balancing.
+ * The FULL report may remain when rsoc drops from 100%.
+ */
+ if (battery_status & BAT_STATUS_FULL) {
+ pr_debug("Battery report Full.\n");
+ bq28400_enable_charging(bq28400_dev, false);
+ return POWER_SUPPLY_STATUS_FULL;
+ }
+
+ rsoc = bq28400_read_rsoc(client);
+ current_ma = bq28400_read_current(client);
+
+ if (rsoc == 100) {
+ bq28400_enable_charging(bq28400_dev, false);
+ pr_debug("Full.\n");
+ return POWER_SUPPLY_STATUS_FULL;
+ }
+
+ /*
+ * Positive current indicates charging
+ * Negative current indicates discharging.
+ * Charging is stopped at termination-current.
+ */
+ if (current_ma < 0) {
+ bq28400_enable_charging(bq28400_dev, true);
+ pr_debug("Discharging.\n");
+ status = POWER_SUPPLY_STATUS_DISCHARGING;
+ } else if (current_ma > BQ_TERMINATION_CURRENT_MA) {
+ pr_debug("Charging.\n");
+ status = POWER_SUPPLY_STATUS_CHARGING;
+ } else {
+ pr_debug("Not Charging.\n");
+ status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ }
+
+ return status;
+}
+
+static int bq28400_get_prop_charge_type(struct i2c_client *client)
+{
+ u16 battery_status;
+ u16 chg_status;
+ u16 fet_status;
+
+ battery_status = bq28400_read_reg(client, SBS_BATTERY_STATUS);
+ chg_status = bq28400_read_reg(client, SBS_CHARGING_STATUS);
+ fet_status = bq28400_read_reg(client, SBS_FET_STATUS);
+
+ if (battery_status & BAT_STATUS_DISCHARGING) {
+ pr_debug("Discharging.\n");
+ return POWER_SUPPLY_CHARGE_TYPE_NONE;
+ }
+
+ if (fet_status & FET_STATUS_PRECHARGE) {
+ pr_debug("Pre-Charging.\n");
+ return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+ }
+
+ if (chg_status & CHG_STATUS_HOT_TEMP_CHARGING) {
+ pr_debug("Hot-Temp-Charging.\n");
+ return POWER_SUPPLY_CHARGE_TYPE_FAST;
+ }
+
+ if (chg_status & CHG_STATUS_LOW_TEMP_CHARGING) {
+ pr_debug("Low-Temp-Charging.\n");
+ return POWER_SUPPLY_CHARGE_TYPE_FAST;
+ }
+
+ if (chg_status & CHG_STATUS_STD1_TEMP_CHARGING) {
+ pr_debug("STD1-Temp-Charging.\n");
+ return POWER_SUPPLY_CHARGE_TYPE_FAST;
+ }
+
+ if (chg_status & CHG_STATUS_STD2_TEMP_CHARGING) {
+ pr_debug("STD2-Temp-Charging.\n");
+ return POWER_SUPPLY_CHARGE_TYPE_FAST;
+ }
+
+ if (chg_status & CHG_STATUS_BATTERY_DEPLETED)
+ pr_debug("battery_depleted.\n");
+
+ if (chg_status & CHG_STATUS_CELL_BALANCING)
+ pr_debug("cell_balancing.\n");
+
+ if (chg_status & CHG_STATUS_OVERCHARGE) {
+ pr_err("overcharge fault.\n");
+ return POWER_SUPPLY_CHARGE_TYPE_NONE;
+ }
+
+ if (chg_status & CHG_STATUS_SUSPENDED) {
+ pr_info("Suspended.\n");
+ return POWER_SUPPLY_CHARGE_TYPE_NONE;
+ }
+
+ if (chg_status & CHG_STATUS_DISABLED) {
+ pr_info("Disabled.\n");
+ return POWER_SUPPLY_CHARGE_TYPE_NONE;
+ }
+
+ return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+}
+
+static bool bq28400_get_prop_present(struct i2c_client *client)
+{
+ int val;
+
+ val = bq28400_read_reg(client, SBS_BATTERY_STATUS);
+
+ /* If the bq28400 is inside the battery pack
+ * then when battery is removed the i2c transfer will fail.
+ */
+
+ if (val < 0)
+ return false;
+
+ /* TODO - support when bq28400 is not embedded in battery pack */
+
+ return true;
+}
+
+/*
+ * User sapce read the battery info.
+ * Get data online via I2C from the battery gauge.
+ */
+static int bq28400_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ int ret = 0;
+ struct bq28400_device *dev = container_of(psy,
+ struct bq28400_device,
+ batt_psy);
+ struct i2c_client *client = dev->client;
+ static char str[BQ_MAX_STR_LEN];
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = bq28400_get_prop_status(client);
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ val->intval = bq28400_get_prop_charge_type(client);
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = bq28400_get_prop_present(client);
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = bq28400_read_voltage(client);
+ val->intval *= 1000; /* mV to uV */
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = bq28400_read_rsoc(client);
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ /* Positive current indicates drawing */
+ val->intval = -bq28400_read_current(client);
+ val->intval *= 1000; /* mA to uA */
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_AVG:
+ /* Positive current indicates drawing */
+ val->intval = -bq28400_read_avg_current(client);
+ val->intval *= 1000; /* mA to uA */
+ break;
+ case POWER_SUPPLY_PROP_TEMP:
+ val->intval = bq28400_read_temperature(client);
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ val->intval = bq28400_read_full_capacity(client);
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_NOW:
+ val->intval = bq28400_read_remain_capacity(client);
+ break;
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+ break;
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ bq28400_read_string(client, SBS_DEVICE_NAME, str, 20);
+ val->strval = str;
+ break;
+ case POWER_SUPPLY_PROP_MANUFACTURER:
+ bq28400_read_string(client, SBS_MANUFACTURER_NAME, str, 20);
+ val->strval = str;
+ break;
+ default:
+ pr_err(" psp %d Not supoprted.\n", psp);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int bq28400_set_reg(void *data, u64 val)
+{
+ struct debug_reg *dbg = data;
+ u8 reg = dbg->reg;
+ int ret;
+ struct i2c_client *client = bq28400_dev->client;
+
+ ret = bq28400_write_reg(client, reg, val);
+
+ return ret;
+}
+
+static int bq28400_get_reg(void *data, u64 *val)
+{
+ struct debug_reg *dbg = data;
+ u8 reg = dbg->reg;
+ u16 subcmd = dbg->subcmd;
+ int ret;
+ struct i2c_client *client = bq28400_dev->client;
+
+ if (subcmd)
+ ret = bq28400_read_subcmd(client, reg, subcmd);
+ else
+ ret = bq28400_read_reg(client, reg);
+ if (ret < 0)
+ return ret;
+
+ *val = ret;
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(reg_fops, bq28400_get_reg, bq28400_set_reg,
+ "0x%04llx\n");
+
+static int bq28400_create_debugfs_entries(struct bq28400_device *bq28400_dev)
+{
+ int i;
+
+ bq28400_dev->dent = debugfs_create_dir(BQ28400_NAME, NULL);
+ if (IS_ERR(bq28400_dev->dent)) {
+ pr_err("bq28400 driver couldn't create debugfs dir\n");
+ return -EFAULT;
+ }
+
+ for (i = 0 ; i < ARRAY_SIZE(bq28400_debug_regs) ; i++) {
+ char *name = bq28400_debug_regs[i].name;
+ struct dentry *file;
+ void *data = &bq28400_debug_regs[i];
+
+ file = debugfs_create_file(name, 0644, bq28400_dev->dent,
+ data, ®_fops);
+ if (IS_ERR(file)) {
+ pr_err("debugfs_create_file %s failed.\n", name);
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
+
+static int bq28400_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ pr_debug("psp = %d.val = %d.\n", psp, val->intval);
+
+ return -EINVAL;
+}
+
+static void bq28400_external_power_changed(struct power_supply *psy)
+{
+ pr_debug("Notify power_supply_changed.\n");
+ /* Update LEDs and notify uevents */
+ power_supply_changed(&bq28400_dev->batt_psy);
+}
+
+static int __devinit bq28400_register_psy(struct bq28400_device *bq28400_dev)
+{
+ int ret;
+
+ bq28400_dev->batt_psy.name = "battery";
+ bq28400_dev->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
+ bq28400_dev->batt_psy.num_supplicants = 0;
+ bq28400_dev->batt_psy.properties = pm_power_props;
+ bq28400_dev->batt_psy.num_properties = ARRAY_SIZE(pm_power_props);
+ bq28400_dev->batt_psy.get_property = bq28400_get_property;
+ bq28400_dev->batt_psy.set_property = bq28400_set_property;
+ bq28400_dev->batt_psy.external_power_changed =
+ bq28400_external_power_changed;
+
+ ret = power_supply_register(&bq28400_dev->client->dev,
+ &bq28400_dev->batt_psy);
+ if (ret) {
+ pr_err("failed to register power_supply. ret=%d.\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * Update userspace every 1 minute.
+ * Normally it takes more than 120 minutes (two hours) to
+ * charge/discahrge the battery,
+ * so updating every 1 minute should be enough for 1% change
+ * detection.
+ * Any immidiate change detected by the DC charger is notified
+ * by the bq28400_external_power_changed callback, which notify
+ * the user space.
+ */
+static void bq28400_periodic_user_space_update_worker(struct work_struct *work)
+{
+ u32 delay_msec = 60*1000;
+
+ pr_debug("Notify user space.\n");
+
+ /* Notify user space via kobject_uevent change notification */
+ power_supply_changed(&bq28400_dev->batt_psy);
+
+ schedule_delayed_work(&bq28400_dev->periodic_user_space_update_work,
+ round_jiffies_relative(msecs_to_jiffies
+ (delay_msec)));
+}
+
+static int __devinit bq28400_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA)) {
+ pr_err(" i2c func fail.\n");
+ return -EIO;
+ }
+
+ bq28400_dev = kzalloc(sizeof(*bq28400_dev), GFP_KERNEL);
+ if (!bq28400_dev) {
+ pr_err(" alloc fail.\n");
+ return -ENOMEM;
+ }
+
+ bq28400_dev->client = client;
+ i2c_set_clientdata(client, bq28400_dev);
+
+ ret = bq28400_register_psy(bq28400_dev);
+ if (ret) {
+ pr_err(" bq28400_register_psy fail.\n");
+ goto err_register_psy;
+ }
+
+ ret = bq28400_create_debugfs_entries(bq28400_dev);
+ if (ret) {
+ pr_err(" bq28400_create_debugfs_entries fail.\n");
+ goto err_debugfs;
+ }
+
+ INIT_DELAYED_WORK(&bq28400_dev->periodic_user_space_update_work,
+ bq28400_periodic_user_space_update_worker);
+
+ schedule_delayed_work(&bq28400_dev->periodic_user_space_update_work,
+ msecs_to_jiffies(1000));
+
+ pr_info("Device is ready.\n");
+
+ return 0;
+
+err_debugfs:
+ if (bq28400_dev->dent)
+ debugfs_remove_recursive(bq28400_dev->dent);
+ power_supply_unregister(&bq28400_dev->batt_psy);
+err_register_psy:
+ kfree(bq28400_dev);
+ bq28400_dev = NULL;
+
+ pr_info("FAIL.\n");
+
+ return ret;
+}
+
+static int __devexit bq28400_remove(struct i2c_client *client)
+{
+ struct bq28400_device *bq28400_dev = i2c_get_clientdata(client);
+
+ power_supply_unregister(&bq28400_dev->batt_psy);
+ if (bq28400_dev->dent)
+ debugfs_remove_recursive(bq28400_dev->dent);
+ kfree(bq28400_dev);
+ bq28400_dev = NULL;
+
+ return 0;
+}
+
+static const struct of_device_id bq28400_match[] = {
+ { .compatible = "ti,bq28400-battery", },
+ { },
+ };
+
+static const struct i2c_device_id bq28400_id[] = {
+ {BQ28400_NAME, 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, bq28400_id);
+
+static struct i2c_driver bq28400_driver = {
+ .driver = {
+ .name = BQ28400_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(bq28400_match),
+ },
+ .probe = bq28400_probe,
+ .remove = __devexit_p(bq28400_remove),
+ .id_table = bq28400_id,
+};
+
+static int __init bq28400_init(void)
+{
+ pr_info(" bq28400 driver rev %s.\n", BQ28400_REV);
+
+ return i2c_add_driver(&bq28400_driver);
+}
+module_init(bq28400_init);
+
+static void __exit bq28400_exit(void)
+{
+ return i2c_del_driver(&bq28400_driver);
+}
+module_exit(bq28400_exit);
+
+MODULE_DESCRIPTION("Driver for BQ28400 charger chip");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("i2c:" BQ28400_NAME);
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 3977f17..8c561b9b 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -289,6 +289,7 @@
bool has_dc_supply;
u8 active_path;
int recent_reported_soc;
+ int battery_less_hardware;
};
/* user space parameter to limit usb current */
@@ -985,30 +986,6 @@
PM8921_CHG_LED_SRC_CONFIG_MASK, temp);
}
-static void disable_input_voltage_regulation(struct pm8921_chg_chip *chip)
-{
- u8 temp;
- int rc;
-
- rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x70);
- if (rc) {
- pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
- return;
- }
- rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
- if (rc) {
- pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
- return;
- }
- /* set the input voltage disable bit and the write bit */
- temp |= 0x81;
- rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
- if (rc) {
- pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
- return;
- }
-}
-
static void enable_input_voltage_regulation(struct pm8921_chg_chip *chip)
{
u8 temp;
@@ -1420,6 +1397,9 @@
{
int percent_soc;
+ if (chip->battery_less_hardware)
+ return 100;
+
if (!get_prop_batt_present(chip))
percent_soc = voltage_based_capacity(chip);
else
@@ -1582,6 +1562,9 @@
int rc;
struct pm8xxx_adc_chan_result result;
+ if (chip->battery_less_hardware)
+ return 300;
+
rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
if (rc) {
pr_err("error reading adc channel = %d, rc = %d\n",
@@ -1710,7 +1693,7 @@
}
/* Check if IUSB_FINE_RES is available */
- if ((usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
+ while ((usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
&& !the_chip->iusb_fine_res)
i--;
if (i < 0)
@@ -2587,29 +2570,49 @@
return IRQ_HANDLED;
}
-static int param_vin_disable_counter = 5;
-module_param(param_vin_disable_counter, int, 0644);
+enum {
+ PON_TIME_25NS = 0x04,
+ PON_TIME_50NS = 0x08,
+ PON_TIME_100NS = 0x0C,
+};
-static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip,
- int count, int usb_ma)
+static void set_min_pon_time(struct pm8921_chg_chip *chip, int pon_time_ns)
{
- if (usb_ma)
- __pm8921_charger_vbus_draw(500);
- pr_debug("count = %d iusb=500mA\n", count);
- disable_input_voltage_regulation(chip);
- pr_debug("count = %d disable_input_regulation\n", count);
+ u8 temp;
+ int rc;
- msleep(20);
+ rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x40);
+ if (rc) {
+ pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
+ return;
+ }
+ rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
+ if (rc) {
+ pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
+ return;
+ }
+ /* clear the min pon time select bit */
+ temp &= 0xF3;
+ /* set the pon time */
+ temp |= (u8)pon_time_ns;
+ /* write enable bank 4 */
+ temp |= 0x80;
+ rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
+ if (rc) {
+ pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
+ return;
+ }
+}
- pr_debug("count = %d end sleep 20ms chg_gone=%d, usb_valid = %d\n",
- count,
- pm_chg_get_rt_status(chip, CHG_GONE_IRQ),
- is_usb_chg_plugged_in(chip));
- pr_debug("count = %d restoring input regulation and usb_ma = %d\n",
- count, usb_ma);
- enable_input_voltage_regulation(chip);
- if (usb_ma)
- __pm8921_charger_vbus_draw(usb_ma);
+static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip)
+{
+ pr_debug("Start\n");
+ set_min_pon_time(chip, PON_TIME_100NS);
+ pm_chg_vinmin_set(chip, chip->vin_min + 200);
+ msleep(250);
+ pm_chg_vinmin_set(chip, chip->vin_min);
+ set_min_pon_time(chip, PON_TIME_25NS);
+ pr_debug("End\n");
}
#define VIN_ACTIVE_BIT BIT(0)
@@ -2640,11 +2643,6 @@
pr_debug("USB charger active\n");
pm_chg_iusbmax_get(chip, &usb_ma);
- if (usb_ma == 500 && !usb_target_ma) {
- pr_debug("Stopping Unplug Check Worker USB == 500mA\n");
- disable_input_voltage_regulation(chip);
- return;
- }
if (usb_ma <= 100) {
pr_debug(
@@ -2654,8 +2652,10 @@
}
} else if (active_path & DC_ACTIVE_BIT) {
pr_debug("DC charger active\n");
- /* Some board designs are not prone to reverse boost on DC
- * charging path */
+ /*
+ * Some board designs are not prone to reverse boost on DC
+ * charging path
+ */
if (!chip->dc_unplug_check)
return;
} else {
@@ -2694,27 +2694,17 @@
ibat = get_prop_batt_current(chip);
if (reg_loop & VIN_ACTIVE_BIT) {
- pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
- ibat, pm_chg_get_fsm_state(chip), reg_loop);
if (ibat > 0) {
- int count = 0;
-
- while (count++ < param_vin_disable_counter
- && active_chg_plugged_in == 1) {
- if (active_path & USB_ACTIVE_BIT)
- attempt_reverse_boost_fix(chip,
- count, usb_ma);
- else
- attempt_reverse_boost_fix(chip,
- count, 0);
- /* after reverse boost fix check if the active
- * charger was detected as removed */
- active_chg_plugged_in
- = is_active_chg_plugged_in(chip,
- active_path);
- pr_debug("active_chg_plugged_in = %d\n",
- active_chg_plugged_in);
- }
+ pr_debug("revboost ibat = %d fsm = %d loop = 0x%x\n",
+ ibat, pm_chg_get_fsm_state(chip), reg_loop);
+ attempt_reverse_boost_fix(chip);
+ /* after reverse boost fix check if the active
+ * charger was detected as removed */
+ active_chg_plugged_in
+ = is_active_chg_plugged_in(chip,
+ active_path);
+ pr_debug("revboost post: active_chg_plugged_in = %d\n",
+ active_chg_plugged_in);
}
}
@@ -4288,6 +4278,10 @@
chip->rconn_mohm = pdata->rconn_mohm;
chip->led_src_config = pdata->led_src_config;
chip->has_dc_supply = pdata->has_dc_supply;
+ chip->battery_less_hardware = pdata->battery_less_hardware;
+
+ if (chip->battery_less_hardware)
+ charging_disabled = 1;
rc = pm8921_chg_hw_init(chip);
if (rc) {
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index ef555f7..bc012ca 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -189,6 +189,7 @@
bool chg_done;
bool usb_present;
bool dc_present;
+ bool charging_disabled;
unsigned int max_bat_chg_current;
unsigned int safe_voltage_mv;
unsigned int max_voltage_mv;
@@ -202,9 +203,6 @@
uint32_t flags;
};
-static struct qpnp_chg_chip *the_chip;
-static bool charging_disabled;
-
static struct of_device_id qpnp_charger_match_table[] = {
{ .compatible = QPNP_CHARGER_DEV_NAME, },
{}
@@ -424,6 +422,20 @@
return IRQ_HANDLED;
}
+static int
+qpnp_batt_property_is_writeable(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CHARGING_ENABLED:
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static enum power_supply_property pm_power_props_mains[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_ONLINE,
@@ -462,7 +474,7 @@
case POWER_SUPPLY_PROP_PRESENT:
case POWER_SUPPLY_PROP_ONLINE:
val->intval = 0;
- if (charging_disabled)
+ if (chip->charging_disabled)
return 0;
val->intval = qpnp_chg_is_dc_chg_plugged_in(chip);
@@ -753,7 +765,7 @@
val->intval = get_prop_full_design(chip);
break;
case POWER_SUPPLY_PROP_CHARGING_ENABLED:
- val->intval = !charging_disabled;
+ val->intval = !(chip->charging_disabled);
break;
default:
return -EINVAL;
@@ -776,7 +788,7 @@
qpnp_chg_charge_en(chip, val->intval);
else
qpnp_chg_charge_dis(chip, val->intval);
- charging_disabled = !(val->intval);
+ chip->charging_disabled = !(val->intval);
break;
default:
return -EINVAL;
@@ -786,25 +798,6 @@
return 0;
}
-static int
-qpnp_chg_set_disable_status_param(const char *val, struct kernel_param *kp)
-{
- int ret;
- struct qpnp_chg_chip *chip = the_chip;
-
- ret = param_set_int(val, kp);
- if (ret) {
- pr_err("error setting value %d\n", ret);
- return ret;
- }
- pr_info("factory set disable param to %d\n", charging_disabled);
- if (chip)
- qpnp_chg_charge_dis(chip, charging_disabled);
- return 0;
-}
-module_param_call(disabled, qpnp_chg_set_disable_status_param, param_get_bool,
- &charging_disabled, 0644);
-
#define QPNP_CHG_VINMIN_MIN_MV 3400
#define QPNP_CHG_VINMIN_HIGH_MIN_MV 5600
#define QPNP_CHG_VINMIN_HIGH_MIN_VAL 0x2B
@@ -1146,7 +1139,7 @@
}
/* Get the charging-disabled property */
- charging_disabled = of_property_read_bool(spmi->dev.of_node,
+ chip->charging_disabled = of_property_read_bool(spmi->dev.of_node,
"qcom,chg-charging-disabled");
spmi_for_each_container_dev(spmi_resource, spmi) {
@@ -1259,6 +1252,7 @@
chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props);
chip->batt_psy.get_property = qpnp_batt_power_get_property;
chip->batt_psy.set_property = qpnp_batt_power_set_property;
+ chip->batt_psy.property_is_writeable = qpnp_batt_property_is_writeable;
chip->batt_psy.external_power_changed =
qpnp_batt_external_power_changed;
@@ -1280,9 +1274,8 @@
power_supply_set_present(chip->usb_psy,
qpnp_chg_is_usb_chg_plugged_in(chip));
- qpnp_chg_charge_en(chip, 1);
- the_chip = chip;
- qpnp_chg_charge_dis(chip, charging_disabled);
+ qpnp_chg_charge_en(chip, !chip->charging_disabled);
+ qpnp_chg_charge_dis(chip, chip->charging_disabled);
pr_info("Probe success !\n");
return 0;
diff --git a/drivers/power/smb350_charger.c b/drivers/power/smb350_charger.c
new file mode 100644
index 0000000..93e208c
--- /dev/null
+++ b/drivers/power/smb350_charger.c
@@ -0,0 +1,865 @@
+/* Copyright (c) 2012 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/power_supply.h>
+#include <linux/i2c/smb350.h>
+#include <linux/bitops.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/printk.h>
+
+/* Register definitions */
+#define CHG_CURRENT_REG 0x00 /* Non-Volatile + mirror */
+#define CHG_OTHER_CURRENT_REG 0x01 /* Non-Volatile + mirror */
+#define VAR_FUNC_REG 0x02 /* Non-Volatile + mirror */
+#define FLOAT_VOLTAGE_REG 0x03 /* Non-Volatile + mirror */
+#define CHG_CTRL_REG 0x04 /* Non-Volatile + mirror */
+#define STAT_TIMER_REG 0x05 /* Non-Volatile + mirror */
+#define PIN_ENABLE_CTRL_REG 0x06 /* Non-Volatile + mirror */
+#define THERM_CTRL_A_REG 0x07 /* Non-Volatile + mirror */
+#define SYSOK_USB3_SELECT_REG 0x08 /* Non-Volatile + mirror */
+#define CTRL_FUNCTIONS_REG 0x09 /* Non-Volatile + mirror */
+#define OTG_TLIM_THERM_CNTRL_REG 0x0A /* Non-Volatile + mirror */
+#define TEMP_MONITOR_REG 0x0B /* Non-Volatile + mirror */
+#define FAULT_IRQ_REG 0x0C /* Non-Volatile */
+#define IRQ_ENABLE_REG 0x0D /* Non-Volatile */
+#define SYSOK_REG 0x0E /* Non-Volatile + mirror */
+
+#define AUTO_INPUT_VOLT_DETECT_REG 0x10 /* Non-Volatile Read-Only */
+#define STATUS_IRQ_REG 0x11 /* Non-Volatile Read-Only */
+#define I2C_SLAVE_ADDR_REG 0x12 /* Non-Volatile Read-Only */
+
+#define CMD_A_REG 0x30 /* Volatile Read-Write */
+#define CMD_B_REG 0x31 /* Volatile Read-Write */
+#define CMD_C_REG 0x33 /* Volatile Read-Write */
+
+#define IRQ_STATUS_A_REG 0x35 /* Volatile Read-Only */
+#define IRQ_STATUS_B_REG 0x36 /* Volatile Read-Only */
+#define IRQ_STATUS_C_REG 0x37 /* Volatile Read-Only */
+#define IRQ_STATUS_D_REG 0x38 /* Volatile Read-Only */
+#define IRQ_STATUS_E_REG 0x39 /* Volatile Read-Only */
+#define IRQ_STATUS_F_REG 0x3A /* Volatile Read-Only */
+
+#define STATUS_A_REG 0x3B /* Volatile Read-Only */
+#define STATUS_B_REG 0x3D /* Volatile Read-Only */
+/* Note: STATUS_C_REG was removed from SMB349 to SMB350 */
+#define STATUS_D_REG 0x3E /* Volatile Read-Only */
+#define STATUS_E_REG 0x3F /* Volatile Read-Only */
+
+#define IRQ_STATUS_NUM (IRQ_STATUS_F_REG - IRQ_STATUS_A_REG + 1)
+
+/* Status bits and masks */
+#define SMB350_MASK(BITS, POS) ((u8)(((1 << BITS) - 1) << POS))
+#define FAST_CHG_CURRENT_MASK SMB350_MASK(4, 4)
+
+#define SMB350_FAST_CHG_MIN_MA 1000
+#define SMB350_FAST_CHG_STEP_MA 200
+#define SMB350_FAST_CHG_MAX_MA 3600
+
+#define TERM_CURRENT_MASK SMB350_MASK(3, 2)
+
+#define SMB350_TERM_CUR_MIN_MA 200
+#define SMB350_TERM_CUR_STEP_MA 100
+#define SMB350_TERM_CUR_MAX_MA 700
+
+#define CMD_A_VOLATILE_WR_PERM BIT(7)
+#define CHG_CTRL_CURR_TERM_END_CHG BIT(6)
+
+enum smb350_chg_status {
+ SMB_CHG_STATUS_NONE = 0,
+ SMB_CHG_STATUS_PRE_CHARGE = 1,
+ SMB_CHG_STATUS_FAST_CHARGE = 2,
+ SMB_CHG_STATUS_TAPER_CHARGE = 3,
+};
+
+static const char * const smb350_chg_status[] = {
+ "none",
+ "pre-charge",
+ "fast-charge",
+ "taper-charge"
+};
+
+struct smb350_device {
+ /* setup */
+ int chg_current_ma;
+ int term_current_ma;
+ int chg_en_n_gpio;
+ int chg_susp_n_gpio;
+ int stat_gpio;
+ int irq;
+ /* internal */
+ enum smb350_chg_status chg_status;
+ struct i2c_client *client;
+ struct delayed_work irq_work;
+ struct dentry *dent;
+ struct wake_lock chg_wake_lock;
+ struct power_supply dc_psy;
+};
+
+static struct smb350_device *smb350_dev;
+
+struct debug_reg {
+ char *name;
+ u8 reg;
+};
+
+#define SMB350_DEBUG_REG(x) {#x, x##_REG}
+
+static struct debug_reg smb350_debug_regs[] = {
+ SMB350_DEBUG_REG(CHG_CURRENT),
+ SMB350_DEBUG_REG(CHG_OTHER_CURRENT),
+ SMB350_DEBUG_REG(VAR_FUNC),
+ SMB350_DEBUG_REG(FLOAT_VOLTAGE),
+ SMB350_DEBUG_REG(CHG_CTRL),
+ SMB350_DEBUG_REG(STAT_TIMER),
+ SMB350_DEBUG_REG(PIN_ENABLE_CTRL),
+ SMB350_DEBUG_REG(THERM_CTRL_A),
+ SMB350_DEBUG_REG(SYSOK_USB3_SELECT),
+ SMB350_DEBUG_REG(CTRL_FUNCTIONS),
+ SMB350_DEBUG_REG(OTG_TLIM_THERM_CNTRL),
+ SMB350_DEBUG_REG(TEMP_MONITOR),
+ SMB350_DEBUG_REG(FAULT_IRQ),
+ SMB350_DEBUG_REG(IRQ_ENABLE),
+ SMB350_DEBUG_REG(SYSOK),
+ SMB350_DEBUG_REG(AUTO_INPUT_VOLT_DETECT),
+ SMB350_DEBUG_REG(STATUS_IRQ),
+ SMB350_DEBUG_REG(I2C_SLAVE_ADDR),
+ SMB350_DEBUG_REG(CMD_A),
+ SMB350_DEBUG_REG(CMD_B),
+ SMB350_DEBUG_REG(CMD_C),
+ SMB350_DEBUG_REG(IRQ_STATUS_A),
+ SMB350_DEBUG_REG(IRQ_STATUS_B),
+ SMB350_DEBUG_REG(IRQ_STATUS_C),
+ SMB350_DEBUG_REG(IRQ_STATUS_D),
+ SMB350_DEBUG_REG(IRQ_STATUS_E),
+ SMB350_DEBUG_REG(IRQ_STATUS_F),
+ SMB350_DEBUG_REG(STATUS_A),
+ SMB350_DEBUG_REG(STATUS_B),
+ SMB350_DEBUG_REG(STATUS_D),
+ SMB350_DEBUG_REG(STATUS_E),
+};
+
+/*
+ * Read 8-bit register value. return negative value on error.
+ */
+static int smb350_read_reg(struct i2c_client *client, u8 reg)
+{
+ int val;
+
+ val = i2c_smbus_read_byte_data(client, reg);
+ if (val < 0)
+ pr_err("i2c read fail. reg=0x%x.ret=%d.\n", reg, val);
+ else
+ pr_debug("reg=0x%02X.val=0x%02X.\n", reg , val);
+
+ return val;
+}
+
+/*
+ * Write 8-bit register value. return negative value on error.
+ */
+static int smb350_write_reg(struct i2c_client *client, u8 reg, u8 val)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, reg, val);
+ if (ret < 0)
+ pr_err("i2c read fail. reg=0x%x.val=0x%x.ret=%d.\n",
+ reg, val, ret);
+ else
+ pr_debug("reg=0x%02X.val=0x%02X.\n", reg , val);
+
+ return ret;
+}
+
+static int smb350_masked_write(struct i2c_client *client, int reg, u8 mask,
+ u8 val)
+{
+ int ret;
+ int temp;
+ int shift = find_first_bit((unsigned long *) &mask, 8);
+
+ temp = smb350_read_reg(client, reg);
+ if (temp < 0)
+ return temp;
+
+ temp &= ~mask;
+ temp |= (val << shift) & mask;
+ ret = smb350_write_reg(client, reg, temp);
+
+ return ret;
+}
+
+#define SMB350_FLOAT_VOLT_BASE_MV 6920
+#define SMB350_FLOAT_VOLT_STEP_MV 40
+#define SMB350_FLOAT_VOLT_MAX_MV (6920 + 0x2F * 40)
+
+/* Fast-to-Taper charging volatge */
+static int smb350_get_float_voltage(struct i2c_client *client)
+{
+ u16 val = smb350_read_reg(client, STATUS_A_REG);
+
+ val = SMB350_FLOAT_VOLT_BASE_MV +
+ ((val & 0x2F) * SMB350_FLOAT_VOLT_STEP_MV);
+
+ return val;
+}
+
+static bool smb350_is_dc_present(struct i2c_client *client)
+{
+ u16 irq_status_f = smb350_read_reg(client, IRQ_STATUS_F_REG);
+ bool power_ok = irq_status_f & 0x01;
+
+ /* Power-ok , IRQ_STATUS_F_REG bit#0 */
+ if (power_ok)
+ pr_debug("DC is present.\n");
+ else
+ pr_debug("DC is missing.\n");
+
+ return power_ok;
+}
+
+static bool smb350_is_charging(struct i2c_client *client)
+{
+ int val;
+ bool is_charging;
+
+ val = smb350_read_reg(client, STATUS_B_REG);
+ if (val < 0)
+ return false;
+
+ val = (val >> 1) & 0x3;
+
+ is_charging = (val != 0);
+
+ return is_charging;
+}
+
+static int smb350_get_prop_charge_type(struct smb350_device *dev)
+{
+ int status_b;
+ enum smb350_chg_status status;
+ int chg_type = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+ bool chg_enabled;
+ bool charger_err;
+ struct i2c_client *client = dev->client;
+
+ status_b = smb350_read_reg(client, STATUS_B_REG);
+ if (status_b < 0) {
+ pr_err("failed to read STATUS_B_REG.\n");
+ return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+ }
+
+ chg_enabled = (bool) (status_b & 0x01);
+ charger_err = (bool) (status_b & (1<<6));
+
+ if (!chg_enabled) {
+ pr_warn("Charging not enabled.\n");
+ return POWER_SUPPLY_CHARGE_TYPE_NONE;
+ }
+
+ if (charger_err) {
+ pr_warn("Charger error detected.\n");
+ return POWER_SUPPLY_CHARGE_TYPE_NONE;
+ }
+
+ status = (status_b >> 1) & 0x3;
+
+ if (status == SMB_CHG_STATUS_NONE)
+ chg_type = POWER_SUPPLY_CHARGE_TYPE_NONE;
+ else if (status == SMB_CHG_STATUS_FAST_CHARGE) /* constant current */
+ chg_type = POWER_SUPPLY_CHARGE_TYPE_FAST;
+ else if (status == SMB_CHG_STATUS_TAPER_CHARGE) /* constant voltage */
+ chg_type = POWER_SUPPLY_CHARGE_TYPE_FAST;
+ else if (status == SMB_CHG_STATUS_PRE_CHARGE)
+ chg_type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+
+ pr_debug("smb-chg-status=%d=%s.\n", status, smb350_chg_status[status]);
+
+ if (dev->chg_status != status) { /* Status changed */
+ if (status == SMB_CHG_STATUS_NONE) {
+ pr_debug("Charging stopped.\n");
+ wake_unlock(&dev->chg_wake_lock);
+ } else {
+ pr_debug("Charging started.\n");
+ wake_lock(&dev->chg_wake_lock);
+ }
+ }
+
+ dev->chg_status = status;
+
+ return chg_type;
+}
+
+static void smb350_enable_charging(struct smb350_device *dev, bool enable)
+{
+ int val = !enable; /* active low */
+
+ pr_debug("enable=%d.\n", enable);
+
+ gpio_set_value_cansleep(dev->chg_en_n_gpio, val);
+}
+
+/* When the status bit of a certain condition is read,
+ * the corresponding IRQ signal is cleared.
+ */
+static int smb350_clear_irq(struct i2c_client *client)
+{
+ int ret;
+
+ ret = smb350_read_reg(client, IRQ_STATUS_A_REG);
+ if (ret < 0)
+ return ret;
+ ret = smb350_read_reg(client, IRQ_STATUS_B_REG);
+ if (ret < 0)
+ return ret;
+ ret = smb350_read_reg(client, IRQ_STATUS_C_REG);
+ if (ret < 0)
+ return ret;
+ ret = smb350_read_reg(client, IRQ_STATUS_D_REG);
+ if (ret < 0)
+ return ret;
+ ret = smb350_read_reg(client, IRQ_STATUS_E_REG);
+ if (ret < 0)
+ return ret;
+ ret = smb350_read_reg(client, IRQ_STATUS_F_REG);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/*
+ * Do the IRQ work from a thread context rather than interrupt context.
+ * Read status registers to clear interrupt source.
+ * Notify the power-supply driver about change detected.
+ * Relevant events for start/stop charging:
+ * 1. DC insert/remove
+ * 2. End-Of-Charging
+ * 3. Battery insert/remove
+ * 4. Temperture too hot/cold
+ * 5. Charging timeout expired.
+ */
+static void smb350_irq_worker(struct work_struct *work)
+{
+ int ret = 0;
+ struct smb350_device *dev =
+ container_of(work, struct smb350_device, irq_work.work);
+
+ ret = smb350_clear_irq(dev->client);
+ if (ret == 0) { /* Cleared ok */
+ /* Notify Battery-psy about status changed */
+ pr_debug("Notify power_supply_changed.\n");
+ power_supply_changed(&dev->dc_psy);
+ }
+}
+
+/*
+ * The STAT pin is low when charging and high when not charging.
+ * When the smb350 start/stop charging the STAT pin triggers an interrupt.
+ * Interrupt is triggered on both rising or falling edge.
+ */
+static irqreturn_t smb350_irq(int irq, void *dev_id)
+{
+ struct smb350_device *dev = dev_id;
+
+ pr_debug("\n");
+
+ /* I2C transfers API should not run in interrupt context */
+ schedule_delayed_work(&dev->irq_work, msecs_to_jiffies(100));
+
+ return IRQ_HANDLED;
+}
+
+static enum power_supply_property pm_power_props[] = {
+ /* real time */
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ /* fixed */
+ POWER_SUPPLY_PROP_MANUFACTURER,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+};
+
+static char *pm_power_supplied_to[] = {
+ "battery",
+};
+
+static int smb350_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ int ret = 0;
+ struct smb350_device *dev = container_of(psy,
+ struct smb350_device,
+ dc_psy);
+ struct i2c_client *client = dev->client;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = smb350_is_dc_present(client);
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = smb350_is_charging(client);
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ val->intval = smb350_get_prop_charge_type(dev);
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = smb350_get_float_voltage(client);
+ val->intval *= 1000; /* mV to uV */
+ break;
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = SMB350_NAME;
+ break;
+ case POWER_SUPPLY_PROP_MANUFACTURER:
+ val->strval = "Summit Microelectronics";
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ val->intval = dev->chg_current_ma;
+ break;
+ default:
+ pr_err("Invalid prop = %d.\n", psp);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int smb350_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ int ret = 0;
+ struct smb350_device *dev =
+ container_of(psy, struct smb350_device, dc_psy);
+
+ switch (psp) {
+ /*
+ * Allow a smart battery to Start/Stop charging.
+ * i.e. when End-Of-Charging detected.
+ * The SMB350 can be configured to terminate charging
+ * when charge-current reaching Termination-Current.
+ */
+ case POWER_SUPPLY_PROP_ONLINE:
+ smb350_enable_charging(dev, val->intval);
+ break;
+ default:
+ pr_err("Invalid prop = %d.\n", psp);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int smb350_set_chg_current(struct i2c_client *client, int current_ma)
+{
+ int ret;
+ u8 temp;
+
+ if ((current_ma < SMB350_FAST_CHG_MIN_MA) ||
+ (current_ma > SMB350_FAST_CHG_MAX_MA)) {
+ pr_err("invalid current %d mA.\n", current_ma);
+ return -EINVAL;
+ }
+
+ temp = (current_ma - SMB350_FAST_CHG_MIN_MA) / SMB350_FAST_CHG_STEP_MA;
+
+ pr_debug("fast-chg-current=%d mA setting %02x\n", current_ma, temp);
+
+ ret = smb350_masked_write(client, CHG_CURRENT_REG,
+ FAST_CHG_CURRENT_MASK, temp);
+
+ return ret;
+}
+
+static int smb350_set_term_current(struct i2c_client *client, int current_ma)
+{
+ int ret;
+ u8 temp;
+
+ if ((current_ma < SMB350_TERM_CUR_MIN_MA) ||
+ (current_ma > SMB350_TERM_CUR_MAX_MA)) {
+ pr_err("invalid current %d mA to set\n", current_ma);
+ return -EINVAL;
+ }
+
+ temp = (current_ma - SMB350_TERM_CUR_MIN_MA) / SMB350_TERM_CUR_STEP_MA;
+
+ pr_debug("term-current=%d mA setting %02x\n", current_ma, temp);
+
+ ret = smb350_masked_write(client, CHG_OTHER_CURRENT_REG,
+ TERM_CURRENT_MASK, temp);
+
+ return ret;
+}
+
+static int smb350_set_reg(void *data, u64 val)
+{
+ u32 addr = (u32) data;
+ int ret;
+ struct i2c_client *client = smb350_dev->client;
+
+ ret = smb350_write_reg(client, addr, (u8) val);
+
+ return ret;
+}
+
+static int smb350_get_reg(void *data, u64 *val)
+{
+ u32 addr = (u32) data;
+ int ret;
+ struct i2c_client *client = smb350_dev->client;
+
+ ret = smb350_read_reg(client, addr);
+ if (ret < 0)
+ return ret;
+
+ *val = ret;
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(reg_fops, smb350_get_reg, smb350_set_reg, "0x%02llx\n");
+
+static int smb350_create_debugfs_entries(struct smb350_device *dev)
+{
+ int i;
+ dev->dent = debugfs_create_dir(SMB350_NAME, NULL);
+ if (IS_ERR(dev->dent)) {
+ pr_err("smb350 driver couldn't create debugfs dir\n");
+ return -EFAULT;
+ }
+
+ for (i = 0 ; i < ARRAY_SIZE(smb350_debug_regs) ; i++) {
+ char *name = smb350_debug_regs[i].name;
+ u32 reg = smb350_debug_regs[i].reg;
+ struct dentry *file;
+
+ file = debugfs_create_file(name, 0644, dev->dent,
+ (void *) reg, ®_fops);
+ if (IS_ERR(file)) {
+ pr_err("debugfs_create_file %s failed.\n", name);
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
+
+static int smb350_set_volatile_params(struct smb350_device *dev)
+{
+ int ret;
+ struct i2c_client *client = dev->client;
+
+ pr_debug("\n");
+
+ ret = smb350_write_reg(client, CMD_A_REG, CMD_A_VOLATILE_WR_PERM);
+ if (ret) {
+ pr_err("Failed to set VOLATILE_WR_PERM ret=%d\n", ret);
+ return ret;
+ }
+
+ /* Disable SMB350 pulse-IRQ mechanism,
+ * we use interrupts based on charging-status-transition
+ */
+ /* Enable STATUS output (regardless of IRQ-pulses) */
+ smb350_masked_write(client, CMD_A_REG, BIT(0), 0);
+
+ /* Disable LED blinking - avoid periodic irq */
+ smb350_masked_write(client, PIN_ENABLE_CTRL_REG, BIT(7), 0);
+
+ /* Disable Failure SMB-IRQ */
+ ret = smb350_write_reg(client, FAULT_IRQ_REG, 0x00);
+ if (ret) {
+ pr_err("Failed to set FAULT_IRQ_REG ret=%d\n", ret);
+ return ret;
+ }
+
+ /* Disable Event IRQ */
+ ret = smb350_write_reg(client, IRQ_ENABLE_REG, 0x00);
+ if (ret) {
+ pr_err("Failed to set IRQ_ENABLE_REG ret=%d\n", ret);
+ return ret;
+ }
+
+ /* Enable charging/not-charging status output via STAT pin */
+ smb350_masked_write(client, STAT_TIMER_REG, BIT(5), 0);
+
+ /* Disable Automatic Recharge */
+ smb350_masked_write(client, CHG_CTRL_REG, BIT(7), 1);
+
+ /* Set fast-charge current */
+ ret = smb350_set_chg_current(client, dev->chg_current_ma);
+ if (ret) {
+ pr_err("Failed to set FAST_CHG_CURRENT ret=%d\n", ret);
+ return ret;
+ }
+
+ if (dev->term_current_ma > 0) {
+ /* Enable Current Termination */
+ smb350_masked_write(client, CHG_CTRL_REG, BIT(6), 0);
+
+ /* Set Termination current */
+ smb350_set_term_current(client, dev->term_current_ma);
+ } else {
+ /* Disable Current Termination */
+ smb350_masked_write(client, CHG_CTRL_REG, BIT(6), 1);
+ }
+
+ return 0;
+}
+
+static int __devinit smb350_register_psy(struct smb350_device *dev)
+{
+ int ret;
+
+ dev->dc_psy.name = "dc";
+ dev->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
+ dev->dc_psy.supplied_to = pm_power_supplied_to;
+ dev->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
+ dev->dc_psy.properties = pm_power_props;
+ dev->dc_psy.num_properties = ARRAY_SIZE(pm_power_props);
+ dev->dc_psy.get_property = smb350_get_property;
+ dev->dc_psy.set_property = smb350_set_property;
+
+ ret = power_supply_register(&dev->client->dev,
+ &dev->dc_psy);
+ if (ret) {
+ pr_err("failed to register power_supply. ret=%d.\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __devinit smb350_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ const struct smb350_platform_data *pdata;
+ struct device_node *dev_node = client->dev.of_node;
+ struct smb350_device *dev;
+
+ /* STAT pin change on start/stop charging */
+ u32 irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA)) {
+ pr_err("i2c func fail.\n");
+ return -EIO;
+ }
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ pr_err("alloc fail.\n");
+ return -ENOMEM;
+ }
+
+ smb350_dev = dev;
+ dev->client = client;
+
+ if (dev_node) {
+ dev->chg_en_n_gpio =
+ of_get_named_gpio(dev_node, "summit,chg-en-n-gpio", 0);
+ pr_debug("chg_en_n_gpio = %d.\n", dev->chg_en_n_gpio);
+
+ dev->chg_susp_n_gpio =
+ of_get_named_gpio(dev_node,
+ "summit,chg-susp-n-gpio", 0);
+ pr_debug("chg_susp_n_gpio = %d.\n", dev->chg_susp_n_gpio);
+
+ dev->stat_gpio =
+ of_get_named_gpio(dev_node, "summit,stat-gpio", 0);
+ pr_debug("stat_gpio = %d.\n", dev->stat_gpio);
+
+ ret = of_property_read_u32(dev_node, "summit,chg-current-ma",
+ &(dev->chg_current_ma));
+ pr_debug("chg_current_ma = %d.\n", dev->chg_current_ma);
+ if (ret) {
+ pr_err("Unable to read chg_current.\n");
+ return ret;
+ }
+ ret = of_property_read_u32(dev_node, "summit,term-current-ma",
+ &(dev->term_current_ma));
+ pr_debug("term_current_ma = %d.\n", dev->term_current_ma);
+ if (ret) {
+ pr_err("Unable to read term_current_ma.\n");
+ return ret;
+ }
+ } else {
+ pdata = client->dev.platform_data;
+
+ if (pdata == NULL) {
+ pr_err("no platform data.\n");
+ return -EINVAL;
+ }
+
+ dev->chg_en_n_gpio = pdata->chg_en_n_gpio;
+ dev->chg_susp_n_gpio = pdata->chg_susp_n_gpio;
+ dev->stat_gpio = pdata->stat_gpio;
+
+ dev->chg_current_ma = pdata->chg_current_ma;
+ dev->term_current_ma = pdata->term_current_ma;
+ }
+
+ ret = gpio_request(dev->stat_gpio, "smb350_stat");
+ if (ret) {
+ pr_err("gpio_request failed for %d ret=%d\n",
+ dev->stat_gpio, ret);
+ goto err_stat_gpio;
+ }
+ dev->irq = gpio_to_irq(dev->stat_gpio);
+ pr_debug("irq#=%d.\n", dev->irq);
+
+ ret = gpio_request(dev->chg_susp_n_gpio, "smb350_suspend");
+ if (ret) {
+ pr_err("gpio_request failed for %d ret=%d\n",
+ dev->chg_susp_n_gpio, ret);
+ goto err_susp_gpio;
+ }
+
+ ret = gpio_request(dev->chg_en_n_gpio, "smb350_charger_enable");
+ if (ret) {
+ pr_err("gpio_request failed for %d ret=%d\n",
+ dev->chg_en_n_gpio, ret);
+ goto err_en_gpio;
+ }
+
+ i2c_set_clientdata(client, dev);
+
+ pr_debug("set charge-enable + not suspend.\n");
+ gpio_set_value_cansleep(dev->chg_en_n_gpio, 1); /* Disable */
+ msleep(100);
+ gpio_set_value_cansleep(dev->chg_susp_n_gpio, 1); /* Normal */
+ msleep(100); /* Allow the device to exist shutdown */
+
+ smb350_read_reg(client, I2C_SLAVE_ADDR_REG);
+
+ ret = smb350_set_volatile_params(dev);
+ if (ret)
+ goto err_set_params;
+
+ ret = smb350_register_psy(dev);
+ if (ret)
+ goto err_set_params;
+
+ ret = smb350_create_debugfs_entries(dev);
+ if (ret)
+ goto err_debugfs;
+
+ INIT_DELAYED_WORK(&dev->irq_work, smb350_irq_worker);
+ wake_lock_init(&dev->chg_wake_lock,
+ WAKE_LOCK_SUSPEND, SMB350_NAME);
+
+ ret = request_irq(dev->irq, smb350_irq, irq_flags,
+ "smb350_irq", dev);
+ if (ret) {
+ pr_err("request_irq %d failed.ret=%d\n", dev->irq, ret);
+ goto err_irq;
+ }
+
+ smb350_enable_charging(dev, true);
+
+ return 0;
+
+err_irq:
+err_debugfs:
+ if (dev->dent)
+ debugfs_remove_recursive(dev->dent);
+err_set_params:
+ gpio_free(dev->chg_en_n_gpio);
+err_en_gpio:
+ gpio_free(dev->chg_susp_n_gpio);
+err_susp_gpio:
+ gpio_free(dev->stat_gpio);
+err_stat_gpio:
+ kfree(smb350_dev);
+ smb350_dev = NULL;
+
+ pr_info("FAIL.\n");
+
+ return ret;
+}
+
+static int __devexit smb350_remove(struct i2c_client *client)
+{
+ struct smb350_device *dev = i2c_get_clientdata(client);
+
+ power_supply_unregister(&dev->dc_psy);
+ gpio_free(dev->chg_en_n_gpio);
+ gpio_free(dev->chg_susp_n_gpio);
+ if (dev->stat_gpio)
+ gpio_free(dev->stat_gpio);
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+ if (dev->dent)
+ debugfs_remove_recursive(dev->dent);
+ kfree(smb350_dev);
+ smb350_dev = NULL;
+
+ return 0;
+}
+
+static const struct i2c_device_id smb350_id[] = {
+ {SMB350_NAME, 0},
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, smb350_id);
+
+static const struct of_device_id smb350_match[] = {
+ { .compatible = "summit,smb350-charger", },
+ { },
+};
+
+static struct i2c_driver smb350_driver = {
+ .driver = {
+ .name = SMB350_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(smb350_match),
+ },
+ .probe = smb350_probe,
+ .remove = __devexit_p(smb350_remove),
+ .id_table = smb350_id,
+};
+
+static int __init smb350_init(void)
+{
+ return i2c_add_driver(&smb350_driver);
+}
+module_init(smb350_init);
+
+static void __exit smb350_exit(void)
+{
+ return i2c_del_driver(&smb350_driver);
+}
+module_exit(smb350_exit);
+
+MODULE_DESCRIPTION("Driver for SMB350 charger chip");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("i2c:" SMB350_NAME);
diff --git a/drivers/slimbus/Kconfig b/drivers/slimbus/Kconfig
index a6a068d..72bd28a 100644
--- a/drivers/slimbus/Kconfig
+++ b/drivers/slimbus/Kconfig
@@ -16,4 +16,13 @@
help
Select driver for Qualcomm's Slimbus Master Component.
+config SLIMBUS_MSM_NGD
+ tristate "Qualcomm Slimbus Satellite Component"
+ help
+ Select driver for Qualcomm's Slimbus Satellite Component.
+ This is light-weight slimbus controller driver responsible for
+ communicating with slave HW directly over the bus using messaging
+ interface, and communicating with master component residing on ADSP
+ for bandwidth and data-channel management.
+
endif
diff --git a/drivers/slimbus/Makefile b/drivers/slimbus/Makefile
index 674f057..45d6e6e 100644
--- a/drivers/slimbus/Makefile
+++ b/drivers/slimbus/Makefile
@@ -3,3 +3,4 @@
#
obj-$(CONFIG_SLIMBUS) += slimbus.o
obj-$(CONFIG_SLIMBUS_MSM_CTRL) += slim-msm.o slim-msm-ctrl.o
+obj-$(CONFIG_SLIMBUS_MSM_NGD) += slim-msm.o slim-msm-ngd.o
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
new file mode 100644
index 0000000..1f2a95e
--- /dev/null
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -0,0 +1,962 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/slimbus/slimbus.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_slimbus.h>
+#include <linux/timer.h>
+#include <mach/sps.h>
+#include "slim-msm.h"
+#include <mach/qdsp6v2/apr.h>
+
+#define NGD_SLIM_NAME "ngd_msm_ctrl"
+#define SLIM_LA_MGR 0xFF
+#define SLIM_ROOT_FREQ 24576000
+
+#define NGD_BASE_V1(r) (((r) % 2) ? 0x800 : 0xA00)
+#define NGD_BASE_V2(r) (((r) % 2) ? 0x1000 : 0x2000)
+#define NGD_BASE(r, v) ((v) ? NGD_BASE_V2(r) : NGD_BASE_V1(r))
+/* NGD (Non-ported Generic Device) registers */
+enum ngd_reg {
+ NGD_CFG = 0x0,
+ NGD_STATUS = 0x4,
+ NGD_RX_MSGQ_CFG = 0x8,
+ NGD_INT_EN = 0x10,
+ NGD_INT_STAT = 0x14,
+ NGD_INT_CLR = 0x18,
+ NGD_TX_MSG = 0x30,
+ NGD_RX_MSG = 0x70,
+ NGD_IE_STAT = 0xF0,
+ NGD_VE_STAT = 0x100,
+};
+
+enum ngd_msg_cfg {
+ NGD_CFG_ENABLE = 1,
+ NGD_CFG_RX_MSGQ_EN = 1 << 1,
+ NGD_CFG_TX_MSGQ_EN = 1 << 2,
+};
+
+enum ngd_intr {
+ NGD_INT_RECFG_DONE = 1 << 24,
+ NGD_INT_TX_NACKED_2 = 1 << 25,
+ NGD_INT_MSG_BUF_CONTE = 1 << 26,
+ NGD_INT_MSG_TX_INVAL = 1 << 27,
+ NGD_INT_IE_VE_CHG = 1 << 28,
+ NGD_INT_DEV_ERR = 1 << 29,
+ NGD_INT_RX_MSG_RCVD = 1 << 30,
+ NGD_INT_TX_MSG_SENT = 1 << 31,
+};
+
+enum ngd_offsets {
+ NGD_NACKED_MC = 0x7F00000,
+ NGD_ACKED_MC = 0xFE000,
+ NGD_ERROR = 0x1800,
+ NGD_MSGQ_SUPPORT = 0x400,
+ NGD_RX_MSGQ_TIME_OUT = 0x16,
+ NGD_ENUMERATED = 0x1,
+ NGD_TX_BUSY = 0x0,
+};
+
+static irqreturn_t ngd_slim_interrupt(int irq, void *d)
+{
+ struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)d;
+ void __iomem *ngd = dev->base + NGD_BASE(dev->ctrl.nr, dev->ver);
+ u32 stat = readl_relaxed(ngd + NGD_INT_STAT);
+
+ if (stat & NGD_INT_TX_MSG_SENT) {
+ writel_relaxed(NGD_INT_TX_MSG_SENT, ngd + NGD_INT_CLR);
+ /* Make sure interrupt is cleared */
+ mb();
+ if (dev->wr_comp)
+ complete(dev->wr_comp);
+ } else if ((stat & NGD_INT_MSG_BUF_CONTE) ||
+ (stat & NGD_INT_MSG_TX_INVAL) || (stat & NGD_INT_DEV_ERR) ||
+ (stat & NGD_INT_TX_NACKED_2)) {
+ dev_err(dev->dev, "NGD interrupt error:0x%x", stat);
+ writel_relaxed(stat, ngd + NGD_INT_CLR);
+ /* Guarantee that error interrupts are cleared */
+ mb();
+ if (((stat & NGD_INT_TX_NACKED_2) ||
+ (stat & NGD_INT_MSG_TX_INVAL))) {
+ dev->err = -EIO;
+ if (dev->wr_comp)
+ complete(dev->wr_comp);
+ }
+ }
+ if (stat & NGD_INT_RX_MSG_RCVD) {
+ u32 rx_buf[10];
+ u8 len, i;
+ rx_buf[0] = readl_relaxed(ngd + NGD_RX_MSG);
+ len = rx_buf[0] & 0x1F;
+ for (i = 1; i < ((len + 3) >> 2); i++) {
+ rx_buf[i] = readl_relaxed(ngd + NGD_RX_MSG +
+ (4 * i));
+ dev_dbg(dev->dev, "REG-RX data: %x\n", rx_buf[i]);
+ }
+ msm_slim_rx_enqueue(dev, rx_buf, len);
+ writel_relaxed(NGD_INT_RX_MSG_RCVD,
+ ngd + NGD_INT_CLR);
+ /*
+ * Guarantee that CLR bit write goes through before
+ * queuing work
+ */
+ mb();
+ if (dev->use_rx_msgqs)
+ dev_err(dev->dev,
+ "direct message received even with RX MSGQs");
+ else
+ complete(&dev->rx_msgq_notify);
+ }
+ if (stat & NGD_INT_RECFG_DONE) {
+ writel_relaxed(NGD_INT_RECFG_DONE, ngd + NGD_INT_CLR);
+ /* Guarantee RECONFIG DONE interrupt is cleared */
+ mb();
+ /* In satellite mode, just log the reconfig done IRQ */
+ dev_dbg(dev->dev, "reconfig done IRQ for NGD");
+ }
+ if (stat & NGD_INT_IE_VE_CHG) {
+ writel_relaxed(NGD_INT_IE_VE_CHG, ngd + NGD_INT_CLR);
+ /* Guarantee IE VE change interrupt is cleared */
+ mb();
+ dev_err(dev->dev, "NGD IE VE change");
+ }
+ return IRQ_HANDLED;
+}
+
+static int ngd_get_tid(struct slim_controller *ctrl, struct slim_msg_txn *txn,
+ u8 *tid, struct completion *done)
+{
+ struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
+ if (ctrl->last_tid <= 255) {
+ ctrl->txnt = krealloc(ctrl->txnt,
+ (ctrl->last_tid + 1) *
+ sizeof(struct slim_msg_txn *),
+ GFP_KERNEL);
+ if (!ctrl->txnt)
+ return -ENOMEM;
+ dev->msg_cnt = ctrl->last_tid;
+ ctrl->last_tid++;
+ } else {
+ int i;
+ for (i = 0; i < 256; i++) {
+ dev->msg_cnt = ((dev->msg_cnt + 1) & 0xFF);
+ if (ctrl->txnt[dev->msg_cnt] == NULL)
+ break;
+ }
+ if (i >= 256) {
+ dev_err(&ctrl->dev, "out of TID");
+ return -ENOMEM;
+ }
+ }
+ ctrl->txnt[dev->msg_cnt] = txn;
+ txn->tid = dev->msg_cnt;
+ txn->comp = done;
+ *tid = dev->msg_cnt;
+ return 0;
+}
+static int ngd_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
+{
+ DECLARE_COMPLETION_ONSTACK(done);
+ DECLARE_COMPLETION_ONSTACK(tx_sent);
+
+ struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
+ u32 *pbuf;
+ u8 *puc;
+ int ret = 0;
+ int msgv = -1;
+ u8 la = txn->la;
+ u8 wbuf[SLIM_RX_MSGQ_BUF_LEN];
+
+ if (txn->mt == SLIM_MSG_MT_CORE &&
+ (txn->mc >= SLIM_MSG_MC_BEGIN_RECONFIGURATION &&
+ txn->mc <= SLIM_MSG_MC_RECONFIGURE_NOW)) {
+ return 0;
+ }
+ msgv = msm_slim_get_ctrl(dev);
+ mutex_lock(&dev->tx_lock);
+ if (txn->mc != SLIM_USR_MC_REPORT_SATELLITE &&
+ (dev->state == MSM_CTRL_ASLEEP ||
+ dev->state == MSM_CTRL_SLEEPING)) {
+ int timeout;
+ dev_err(dev->dev, "controller not ready");
+ mutex_unlock(&dev->tx_lock);
+ /* Reconf is signalled when master responds */
+ timeout = wait_for_completion_timeout(&dev->reconf, HZ);
+ if (timeout) {
+ mutex_lock(&dev->tx_lock);
+ } else {
+ if (msgv >= 0)
+ msm_slim_put_ctrl(dev);
+ return -EBUSY;
+ }
+ }
+ if (txn->mt == SLIM_MSG_MT_CORE &&
+ (txn->mc == SLIM_MSG_MC_CONNECT_SOURCE ||
+ txn->mc == SLIM_MSG_MC_CONNECT_SINK ||
+ txn->mc == SLIM_MSG_MC_DISCONNECT_PORT)) {
+ int i = 0;
+ txn->mt = SLIM_MSG_MT_DEST_REFERRED_USER;
+ if (txn->mc == SLIM_MSG_MC_CONNECT_SOURCE)
+ txn->mc = SLIM_USR_MC_CONNECT_SRC;
+ else if (txn->mc == SLIM_MSG_MC_CONNECT_SINK)
+ txn->mc = SLIM_USR_MC_CONNECT_SINK;
+ else if (txn->mc == SLIM_MSG_MC_DISCONNECT_PORT)
+ txn->mc = SLIM_USR_MC_DISCONNECT_PORT;
+ if (txn->la == SLIM_LA_MGR)
+ txn->la = dev->pgdla;
+ wbuf[i++] = txn->la;
+ la = SLIM_LA_MGR;
+ wbuf[i++] = txn->wbuf[0];
+ if (txn->mc != SLIM_USR_MC_DISCONNECT_PORT)
+ wbuf[i++] = txn->wbuf[1];
+ ret = ngd_get_tid(ctrl, txn, &wbuf[i++], &done);
+ if (ret) {
+ pr_err("TID for connect/disconnect fail:%d", ret);
+ goto ngd_xfer_err;
+ }
+ txn->len = i;
+ txn->wbuf = wbuf;
+ txn->rl = txn->len + 4;
+ }
+ txn->rl--;
+ pbuf = msm_get_msg_buf(dev, txn->rl);
+ if (!pbuf) {
+ dev_err(dev->dev, "Message buffer unavailable");
+ ret = -ENOMEM;
+ goto ngd_xfer_err;
+ }
+ dev->err = 0;
+
+ if (txn->dt == SLIM_MSG_DEST_ENUMADDR) {
+ ret = -EPROTONOSUPPORT;
+ goto ngd_xfer_err;
+ }
+ if (txn->dt == SLIM_MSG_DEST_LOGICALADDR)
+ *pbuf = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, txn->mc, 0,
+ la);
+ else
+ *pbuf = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, txn->mc, 1,
+ la);
+ if (txn->dt == SLIM_MSG_DEST_LOGICALADDR)
+ puc = ((u8 *)pbuf) + 3;
+ else
+ puc = ((u8 *)pbuf) + 2;
+ if (txn->rbuf)
+ *(puc++) = txn->tid;
+ if ((txn->mt == SLIM_MSG_MT_CORE) &&
+ ((txn->mc >= SLIM_MSG_MC_REQUEST_INFORMATION &&
+ txn->mc <= SLIM_MSG_MC_REPORT_INFORMATION) ||
+ (txn->mc >= SLIM_MSG_MC_REQUEST_VALUE &&
+ txn->mc <= SLIM_MSG_MC_CHANGE_VALUE))) {
+ *(puc++) = (txn->ec & 0xFF);
+ *(puc++) = (txn->ec >> 8)&0xFF;
+ }
+ if (txn->wbuf)
+ memcpy(puc, txn->wbuf, txn->len);
+ if (txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER &&
+ (txn->mc == SLIM_USR_MC_CONNECT_SRC ||
+ txn->mc == SLIM_USR_MC_CONNECT_SINK ||
+ txn->mc == SLIM_USR_MC_DISCONNECT_PORT) && txn->wbuf &&
+ wbuf[0] == dev->pgdla) {
+ if (txn->mc != SLIM_MSG_MC_DISCONNECT_PORT)
+ dev->err = msm_slim_connect_pipe_port(dev, wbuf[1]);
+ else {
+ struct msm_slim_endp *endpoint = &dev->pipes[wbuf[1]];
+ struct sps_register_event sps_event;
+ memset(&sps_event, 0, sizeof(sps_event));
+ sps_register_event(endpoint->sps, &sps_event);
+ sps_disconnect(endpoint->sps);
+ /*
+ * Remove channel disconnects master-side ports from
+ * channel. No need to send that again on the bus
+ */
+ dev->pipes[wbuf[1]].connected = false;
+ mutex_unlock(&dev->tx_lock);
+ if (msgv >= 0)
+ msm_slim_put_ctrl(dev);
+ return 0;
+ }
+ if (dev->err) {
+ dev_err(dev->dev, "pipe-port connect err:%d", dev->err);
+ goto ngd_xfer_err;
+ }
+ }
+ dev->err = 0;
+ dev->wr_comp = &tx_sent;
+ ret = msm_send_msg_buf(dev, pbuf, txn->rl,
+ NGD_BASE(dev->ctrl.nr, dev->ver) + NGD_TX_MSG);
+ if (!ret) {
+ int timeout = wait_for_completion_timeout(&tx_sent, HZ);
+ if (!timeout)
+ ret = -ETIMEDOUT;
+ else
+ ret = dev->err;
+ }
+ dev->wr_comp = NULL;
+ if (ret) {
+ u32 conf, stat, rx_msgq, int_stat, int_en, int_clr;
+ void __iomem *ngd = dev->base + NGD_BASE(dev->ctrl.nr,
+ dev->ver);
+ dev_err(dev->dev, "TX failed :MC:0x%x,mt:0x%x, ret:%d, ver:%d",
+ txn->mc, txn->mt, ret, dev->ver);
+ conf = readl_relaxed(ngd);
+ stat = readl_relaxed(ngd + NGD_STATUS);
+ rx_msgq = readl_relaxed(ngd + NGD_RX_MSGQ_CFG);
+ int_stat = readl_relaxed(ngd + NGD_INT_STAT);
+ int_en = readl_relaxed(ngd + NGD_INT_EN);
+ int_clr = readl_relaxed(ngd + NGD_INT_CLR);
+
+ pr_err("conf:0x%x,stat:0x%x,rxmsgq:0x%x", conf, stat, rx_msgq);
+ pr_err("int_stat:0x%x,int_en:0x%x,int_cll:0x%x", int_stat,
+ int_en, int_clr);
+ } else if (txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER &&
+ (txn->mc == SLIM_USR_MC_CONNECT_SRC ||
+ txn->mc == SLIM_USR_MC_CONNECT_SINK ||
+ txn->mc == SLIM_USR_MC_DISCONNECT_PORT)) {
+ int timeout;
+ mutex_unlock(&dev->tx_lock);
+ if (msgv >= 0)
+ msm_slim_put_ctrl(dev);
+ timeout = wait_for_completion_timeout(txn->comp, HZ);
+ if (!timeout) {
+ pr_err("connect/disc :0x%x, tid:%d timed out", txn->mc,
+ txn->tid);
+ ret = -ETIMEDOUT;
+ } else {
+ ret = txn->ec;
+ }
+ if (ret)
+ pr_err("connect/disconnect:0x%x,tid:%d err:%d", txn->mc,
+ txn->tid, ret);
+ return ret ? ret : dev->err;
+ }
+ngd_xfer_err:
+ mutex_unlock(&dev->tx_lock);
+ if (msgv >= 0)
+ msm_slim_put_ctrl(dev);
+ return ret ? ret : dev->err;
+}
+
+static int ngd_xferandwait_ack(struct slim_controller *ctrl,
+ struct slim_msg_txn *txn)
+{
+ int ret = ngd_xfer_msg(ctrl, txn);
+ if (!ret) {
+ int timeout;
+ timeout = wait_for_completion_timeout(txn->comp, HZ);
+ if (!timeout) {
+ pr_err("master req:0x%x, tid:%d timed out", txn->mc,
+ txn->tid);
+ ret = -ETIMEDOUT;
+ } else {
+ ret = txn->ec;
+ }
+ }
+ if (ret)
+ pr_err("master msg:0x%x,tid:%d ret:%d", txn->mc,
+ txn->tid, ret);
+
+ return ret;
+}
+
+static int ngd_allocbw(struct slim_device *sb, int *subfrmc, int *clkgear)
+{
+ int ret;
+ struct slim_pending_ch *pch;
+ struct slim_msg_txn txn;
+ struct slim_controller *ctrl = sb->ctrl;
+ DECLARE_COMPLETION_ONSTACK(done);
+ u8 wbuf[SLIM_RX_MSGQ_BUF_LEN];
+
+ txn.mt = SLIM_MSG_MT_DEST_REFERRED_USER;
+ txn.dt = SLIM_MSG_DEST_LOGICALADDR;
+ txn.la = SLIM_LA_MGR;
+ txn.len = 0;
+ txn.ec = 0;
+ txn.wbuf = wbuf;
+ txn.rbuf = NULL;
+
+ list_for_each_entry(pch, &sb->mark_define, pending) {
+ struct slim_ich *slc;
+ slc = &ctrl->chans[pch->chan];
+ if (!slc) {
+ pr_err("no channel in define?");
+ return -ENXIO;
+ }
+ if (txn.len == 0) {
+ wbuf[txn.len++] = (u8) (slc->prop.dataf << 5) |
+ sb->laddr;
+ wbuf[txn.len] = slc->seglen;
+ if (slc->coeff == SLIM_COEFF_3)
+ wbuf[txn.len] |= 1 << 5;
+ wbuf[txn.len++] |= slc->prop.auxf << 6;
+ wbuf[txn.len++] = slc->rootexp << 4 | slc->prop.prot;
+ wbuf[txn.len++] = slc->prrate;
+ ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
+ if (ret) {
+ pr_err("no tid for channel define?");
+ return -ENXIO;
+ }
+ }
+ wbuf[txn.len++] = slc->chan;
+ }
+ if (txn.len) {
+ txn.mc = SLIM_USR_MC_DEF_ACT_CHAN;
+ txn.rl = txn.len + 4;
+ ret = ngd_xferandwait_ack(ctrl, &txn);
+ if (ret)
+ return ret;
+
+ txn.mc = SLIM_USR_MC_RECONFIG_NOW;
+ txn.len = 2;
+ wbuf[1] = sb->laddr;
+ txn.rl = txn.len + 4;
+ ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
+ if (ret)
+ return ret;
+ ret = ngd_xferandwait_ack(ctrl, &txn);
+ if (ret)
+ return ret;
+ }
+ txn.len = 0;
+ list_for_each_entry(pch, &sb->mark_removal, pending) {
+ struct slim_ich *slc;
+ slc = &ctrl->chans[pch->chan];
+ if (!slc) {
+ pr_err("no channel in removal?");
+ return -ENXIO;
+ }
+ if (txn.len == 0) {
+ wbuf[txn.len++] = (u8) (SLIM_CH_REMOVE << 6) |
+ sb->laddr;
+ ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
+ if (ret) {
+ pr_err("no tid for channel define?");
+ return -ENXIO;
+ }
+ }
+ wbuf[txn.len++] = slc->chan;
+ }
+ if (txn.len) {
+ txn.mc = SLIM_USR_MC_CHAN_CTRL;
+ txn.rl = txn.len + 4;
+ ret = ngd_xferandwait_ack(ctrl, &txn);
+ if (ret)
+ return ret;
+
+ txn.mc = SLIM_USR_MC_RECONFIG_NOW;
+ txn.len = 2;
+ wbuf[1] = sb->laddr;
+ txn.rl = txn.len + 4;
+ ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
+ if (ret)
+ return ret;
+ ret = ngd_xferandwait_ack(ctrl, &txn);
+ if (ret)
+ return ret;
+ txn.len = 0;
+ }
+ return ret;
+}
+
+static int ngd_set_laddr(struct slim_controller *ctrl, const u8 *ea,
+ u8 elen, u8 laddr)
+{
+ return 0;
+}
+
+static int ngd_get_laddr(struct slim_controller *ctrl, const u8 *ea,
+ u8 elen, u8 *laddr)
+{
+ int ret;
+ u8 wbuf[10];
+ struct slim_msg_txn txn;
+ DECLARE_COMPLETION_ONSTACK(done);
+ txn.mt = SLIM_MSG_MT_DEST_REFERRED_USER;
+ txn.dt = SLIM_MSG_DEST_LOGICALADDR;
+ txn.la = SLIM_LA_MGR;
+ txn.ec = 0;
+ mutex_lock(&ctrl->m_ctrl);
+ ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
+ if (ret) {
+ mutex_unlock(&ctrl->m_ctrl);
+ return ret;
+ }
+ memcpy(&wbuf[1], ea, elen);
+ txn.mc = SLIM_USR_MC_ADDR_QUERY;
+ txn.rl = 11;
+ txn.len = 7;
+ txn.wbuf = wbuf;
+ txn.rbuf = NULL;
+ ret = ngd_xferandwait_ack(ctrl, &txn);
+ if (!ret && txn.la == 0xFF)
+ ret = -ENXIO;
+ else if (!ret)
+ *laddr = txn.la;
+ mutex_unlock(&ctrl->m_ctrl);
+ return ret;
+}
+
+static void ngd_slim_rx(struct msm_slim_ctrl *dev, u8 *buf)
+{
+ u8 mc, mt, len;
+ int ret;
+ u32 msgq_en = 1;
+
+ len = buf[0] & 0x1F;
+ mt = (buf[0] >> 5) & 0x7;
+ mc = buf[1];
+ if (mc == SLIM_USR_MC_MASTER_CAPABILITY &&
+ mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
+ struct slim_msg_txn txn;
+ u8 wbuf[8];
+ txn.dt = SLIM_MSG_DEST_LOGICALADDR;
+ txn.ec = 0;
+ txn.rbuf = NULL;
+ txn.mc = SLIM_USR_MC_REPORT_SATELLITE;
+ txn.mt = SLIM_MSG_MT_SRC_REFERRED_USER;
+ txn.la = SLIM_LA_MGR;
+ txn.rl = 8;
+ wbuf[0] = SAT_MAGIC_LSB;
+ wbuf[1] = SAT_MAGIC_MSB;
+ wbuf[2] = SAT_MSG_VER;
+ wbuf[3] = SAT_MSG_PROT;
+ txn.wbuf = wbuf;
+ txn.len = 4;
+ dev->use_rx_msgqs = 1;
+ msm_slim_sps_init(dev, dev->bam_mem,
+ NGD_BASE(dev->ctrl.nr, dev->ver) + NGD_STATUS, true);
+ if (dev->use_rx_msgqs)
+ msgq_en |= NGD_CFG_RX_MSGQ_EN;
+ writel_relaxed(msgq_en, dev->base +
+ NGD_BASE(dev->ctrl.nr, dev->ver));
+ /* make sure NGD MSG-Q config goes through */
+ mb();
+
+ ret = ngd_xfer_msg(&dev->ctrl, &txn);
+ if (!ret) {
+ dev->state = MSM_CTRL_AWAKE;
+ complete(&dev->reconf);
+ }
+ }
+ if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
+ mc == SLIM_MSG_MC_REPLY_VALUE) {
+ u8 tid = buf[3];
+ dev_dbg(dev->dev, "tid:%d, len:%d\n", tid, len);
+ slim_msg_response(&dev->ctrl, &buf[4], tid,
+ len - 4);
+ pm_runtime_mark_last_busy(dev->dev);
+ }
+ if (mc == SLIM_USR_MC_ADDR_REPLY &&
+ mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
+ struct slim_msg_txn *txn = dev->ctrl.txnt[buf[3]];
+ u8 failed_ea[6] = {0, 0, 0, 0, 0, 0};
+ if (!txn)
+ return;
+ if (memcmp(&buf[4], failed_ea, 6))
+ txn->la = buf[10];
+ dev->ctrl.txnt[buf[3]] = NULL;
+ complete(txn->comp);
+ }
+ if (mc == SLIM_USR_MC_GENERIC_ACK &&
+ mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
+ struct slim_msg_txn *txn = dev->ctrl.txnt[buf[3]];
+ if (!txn)
+ return;
+ dev_dbg(dev->dev, "got response:tid:%d, response:0x%x",
+ (int)buf[3], buf[4]);
+ if (!(buf[4] & MSM_SAT_SUCCSS)) {
+ dev_err(dev->dev, "TID:%d, NACK code:0x%x", (int)buf[3],
+ buf[4]);
+ txn->ec = -EIO;
+ }
+ dev->ctrl.txnt[buf[3]] = NULL;
+ complete(txn->comp);
+ }
+}
+static int ngd_slim_rx_msgq_thread(void *data)
+{
+ struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)data;
+ struct completion *notify = &dev->rx_msgq_notify;
+ int ret = 0, index = 0;
+ u32 mc = 0;
+ u32 mt = 0;
+ u32 buffer[10];
+ u8 msg_len = 0;
+
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ ret = wait_for_completion_interruptible(notify);
+ if (ret) {
+ dev_err(dev->dev, "rx thread wait err:%d", ret);
+ continue;
+ }
+ /* 1 irq notification per message */
+ if (!dev->use_rx_msgqs) {
+ msm_slim_rx_dequeue(dev, (u8 *)buffer);
+ ngd_slim_rx(dev, (u8 *)buffer);
+ continue;
+ }
+ ret = msm_slim_rx_msgq_get(dev, buffer, index);
+ if (ret) {
+ dev_err(dev->dev, "rx_msgq_get() failed 0x%x\n", ret);
+ continue;
+ }
+
+ /* Wait for complete message */
+ if (index++ == 0) {
+ msg_len = *buffer & 0x1F;
+ mt = (buffer[0] >> 5) & 0x7;
+ mc = (buffer[0] >> 8) & 0xff;
+ dev_dbg(dev->dev, "MC: %x, MT: %x\n", mc, mt);
+ }
+ if ((index * 4) >= msg_len) {
+ index = 0;
+ ngd_slim_rx(dev, (u8 *)buffer);
+ } else
+ continue;
+ }
+ return 0;
+}
+
+static int __devinit ngd_slim_probe(struct platform_device *pdev)
+{
+ struct msm_slim_ctrl *dev;
+ int ret;
+ struct resource *bam_mem;
+ struct resource *slim_mem;
+ struct resource *irq, *bam_irq;
+ enum apr_subsys_state q6_state;
+ u32 ngd_int;
+
+ q6_state = apr_get_q6_state();
+ if (q6_state == APR_SUBSYS_DOWN) {
+ dev_dbg(&pdev->dev, "defering %s, adsp_state %d\n", __func__,
+ q6_state);
+ return -EPROBE_DEFER;
+ } else
+ dev_dbg(&pdev->dev, "adsp is ready\n");
+
+ slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "slimbus_physical");
+ if (!slim_mem) {
+ dev_err(&pdev->dev, "no slimbus physical memory resource\n");
+ return -ENODEV;
+ }
+ bam_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "slimbus_bam_physical");
+ if (!bam_mem) {
+ dev_err(&pdev->dev, "no slimbus BAM memory resource\n");
+ return -ENODEV;
+ }
+ irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+ "slimbus_irq");
+ if (!irq) {
+ dev_err(&pdev->dev, "no slimbus IRQ resource\n");
+ return -ENODEV;
+ }
+ bam_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+ "slimbus_bam_irq");
+ if (!bam_irq) {
+ dev_err(&pdev->dev, "no slimbus BAM IRQ resource\n");
+ return -ENODEV;
+ }
+
+ dev = kzalloc(sizeof(struct msm_slim_ctrl), GFP_KERNEL);
+ if (IS_ERR(dev)) {
+ dev_err(&pdev->dev, "no memory for MSM slimbus controller\n");
+ return PTR_ERR(dev);
+ }
+ dev->dev = &pdev->dev;
+ platform_set_drvdata(pdev, dev);
+ slim_set_ctrldata(&dev->ctrl, dev);
+ dev->base = ioremap(slim_mem->start, resource_size(slim_mem));
+ if (!dev->base) {
+ dev_err(&pdev->dev, "IOremap failed\n");
+ ret = -ENOMEM;
+ goto err_ioremap_failed;
+ }
+ dev->bam.base = ioremap(bam_mem->start, resource_size(bam_mem));
+ if (!dev->bam.base) {
+ dev_err(&pdev->dev, "BAM IOremap failed\n");
+ ret = -ENOMEM;
+ goto err_ioremap_bam_failed;
+ }
+ if (pdev->dev.of_node) {
+
+ ret = of_property_read_u32(pdev->dev.of_node, "cell-index",
+ &dev->ctrl.nr);
+ if (ret) {
+ dev_err(&pdev->dev, "Cell index not specified:%d", ret);
+ goto err_ctrl_failed;
+ }
+ } else {
+ dev->ctrl.nr = pdev->id;
+ }
+ dev->ctrl.nchans = MSM_SLIM_NCHANS;
+ dev->ctrl.nports = MSM_SLIM_NPORTS;
+ dev->framer.rootfreq = SLIM_ROOT_FREQ >> 3;
+ dev->framer.superfreq =
+ dev->framer.rootfreq / SLIM_CL_PER_SUPERFRAME_DIV8;
+ dev->ctrl.a_framer = &dev->framer;
+ dev->ctrl.clkgear = SLIM_MAX_CLK_GEAR;
+ dev->ctrl.set_laddr = ngd_set_laddr;
+ dev->ctrl.get_laddr = ngd_get_laddr;
+ dev->ctrl.allocbw = ngd_allocbw;
+ dev->ctrl.xfer_msg = ngd_xfer_msg;
+ dev->ctrl.wakeup = NULL;
+ dev->ctrl.config_port = msm_config_port;
+ dev->ctrl.port_xfer = msm_slim_port_xfer;
+ dev->ctrl.port_xfer_status = msm_slim_port_xfer_status;
+ /* Reserve some messaging BW for satellite-apps driver communication */
+ dev->ctrl.sched.pending_msgsl = 30;
+ dev->bam_mem = bam_mem;
+
+ init_completion(&dev->reconf);
+ mutex_init(&dev->tx_lock);
+ spin_lock_init(&dev->rx_lock);
+ dev->ee = 1;
+ dev->irq = irq->start;
+ dev->bam.irq = bam_irq->start;
+
+ dev->ver = readl_relaxed(dev->base);
+ /* Version info in 16 MSbits */
+ dev->ver >>= 16;
+ ngd_int = (NGD_INT_RECFG_DONE | NGD_INT_TX_NACKED_2 |
+ NGD_INT_MSG_BUF_CONTE | NGD_INT_MSG_TX_INVAL |
+ NGD_INT_IE_VE_CHG | NGD_INT_DEV_ERR |
+ NGD_INT_TX_MSG_SENT | NGD_INT_RX_MSG_RCVD);
+ init_completion(&dev->rx_msgq_notify);
+
+ /* Register with framework */
+ ret = slim_add_numbered_controller(&dev->ctrl);
+ if (ret) {
+ dev_err(dev->dev, "error adding controller\n");
+ goto err_ctrl_failed;
+ }
+
+ dev->ctrl.dev.parent = &pdev->dev;
+ dev->ctrl.dev.of_node = pdev->dev.of_node;
+ dev->state = MSM_CTRL_ASLEEP;
+
+ ret = request_irq(dev->irq, ngd_slim_interrupt,
+ IRQF_TRIGGER_HIGH, "ngd_slim_irq", dev);
+
+ if (ret) {
+ dev_err(&pdev->dev, "request IRQ failed\n");
+ goto err_request_irq_failed;
+ }
+
+ /* Fire up the Rx message queue thread */
+ dev->rx_msgq_thread = kthread_run(ngd_slim_rx_msgq_thread, dev,
+ NGD_SLIM_NAME "_ngd_msgq_thread");
+ if (IS_ERR(dev->rx_msgq_thread)) {
+ ret = PTR_ERR(dev->rx_msgq_thread);
+ dev_err(dev->dev, "Failed to start Rx message queue thread\n");
+ goto err_thread_create_failed;
+ }
+
+ writel_relaxed(ngd_int, dev->base + NGD_INT_EN +
+ NGD_BASE(dev->ctrl.nr, dev->ver));
+ /*
+ * Enable NGD. Configure NGD in register access mode until master
+ * announcement is received
+ */
+ writel_relaxed(1, dev->base + NGD_BASE(dev->ctrl.nr, dev->ver));
+ /* make sure NGD enabling goes through */
+ mb();
+
+ if (pdev->dev.of_node)
+ of_register_slim_devices(&dev->ctrl);
+
+ /* Add devices registered with board-info now that controller is up */
+ slim_ctrl_add_boarddevs(&dev->ctrl);
+
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, MSM_SLIM_AUTOSUSPEND);
+ pm_runtime_set_active(&pdev->dev);
+
+ dev_dbg(dev->dev, "NGD SB controller is up!\n");
+ return 0;
+
+err_thread_create_failed:
+ free_irq(dev->irq, dev);
+err_request_irq_failed:
+ slim_del_controller(&dev->ctrl);
+err_ctrl_failed:
+ iounmap(dev->bam.base);
+err_ioremap_bam_failed:
+ iounmap(dev->base);
+err_ioremap_failed:
+ kfree(dev);
+ return ret;
+}
+
+static int __devexit ngd_slim_remove(struct platform_device *pdev)
+{
+ struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ free_irq(dev->irq, dev);
+ slim_del_controller(&dev->ctrl);
+ kthread_stop(dev->rx_msgq_thread);
+ iounmap(dev->bam.base);
+ iounmap(dev->base);
+ kfree(dev);
+ return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int ngd_slim_runtime_idle(struct device *device)
+{
+ dev_dbg(device, "pm_runtime: idle...\n");
+ pm_request_autosuspend(device);
+ return -EAGAIN;
+}
+#endif
+
+/*
+ * If PM_RUNTIME is not defined, these 2 functions become helper
+ * functions to be called from system suspend/resume. So they are not
+ * inside ifdef CONFIG_PM_RUNTIME
+ */
+#ifdef CONFIG_PM_SLEEP
+static int ngd_slim_runtime_suspend(struct device *device)
+{
+ struct platform_device *pdev = to_platform_device(device);
+ struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
+ int ret;
+ dev_dbg(device, "pm_runtime: suspending...\n");
+ dev->state = MSM_CTRL_SLEEPING;
+ ret = slim_ctrl_clk_pause(&dev->ctrl, false, SLIM_CLK_UNSPECIFIED);
+ if (ret) {
+ dev_err(device, "clk pause not entered:%d", ret);
+ dev->state = MSM_CTRL_AWAKE;
+ } else {
+ dev->state = MSM_CTRL_ASLEEP;
+ }
+ return ret;
+}
+
+static int ngd_slim_runtime_resume(struct device *device)
+{
+ struct platform_device *pdev = to_platform_device(device);
+ struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
+ int ret = 0;
+ dev_dbg(device, "pm_runtime: resuming...\n");
+ if (dev->state == MSM_CTRL_ASLEEP)
+ ret = slim_ctrl_clk_pause(&dev->ctrl, true, 0);
+ if (ret) {
+ dev_err(device, "clk pause not exited:%d", ret);
+ dev->state = MSM_CTRL_ASLEEP;
+ } else {
+ dev->state = MSM_CTRL_AWAKE;
+ }
+ return ret;
+}
+
+static int ngd_slim_suspend(struct device *dev)
+{
+ int ret = -EBUSY;
+ if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
+ dev_dbg(dev, "system suspend");
+ ret = ngd_slim_runtime_suspend(dev);
+ }
+ if (ret == -EBUSY) {
+ /*
+ * There is a possibility that some audio stream is active
+ * during suspend. We dont want to return suspend failure in
+ * that case so that display and relevant components can still
+ * go to suspend.
+ * If there is some other error, then it should be passed-on
+ * to system level suspend
+ */
+ ret = 0;
+ }
+ return ret;
+}
+
+static int ngd_slim_resume(struct device *dev)
+{
+ /* If runtime_pm is enabled, this resume shouldn't do anything */
+ if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
+ int ret;
+ dev_dbg(dev, "system resume");
+ ret = ngd_slim_runtime_resume(dev);
+ if (!ret) {
+ pm_runtime_mark_last_busy(dev);
+ pm_request_autosuspend(dev);
+ }
+ return ret;
+
+ }
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops ngd_slim_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(
+ ngd_slim_suspend,
+ ngd_slim_resume
+ )
+ SET_RUNTIME_PM_OPS(
+ ngd_slim_runtime_suspend,
+ ngd_slim_runtime_resume,
+ ngd_slim_runtime_idle
+ )
+};
+
+static struct of_device_id ngd_slim_dt_match[] = {
+ {
+ .compatible = "qcom,slim-ngd",
+ },
+ {}
+};
+
+static struct platform_driver ngd_slim_driver = {
+ .probe = ngd_slim_probe,
+ .remove = ngd_slim_remove,
+ .driver = {
+ .name = NGD_SLIM_NAME,
+ .owner = THIS_MODULE,
+ .pm = &ngd_slim_dev_pm_ops,
+ .of_match_table = ngd_slim_dt_match,
+ },
+};
+
+static int ngd_slim_init(void)
+{
+ return platform_driver_register(&ngd_slim_driver);
+}
+late_initcall(ngd_slim_init);
+
+static void ngd_slim_exit(void)
+{
+ platform_driver_unregister(&ngd_slim_driver);
+}
+module_exit(ngd_slim_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM Slimbus controller");
+MODULE_ALIAS("platform:msm-slim-ngd");
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index 35bb040..7d50620 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -167,6 +167,7 @@
struct device *dev;
void __iomem *base;
struct resource *slew_mem;
+ struct resource *bam_mem;
u32 curr_bw;
u8 msg_cnt;
u32 tx_buf[10];
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 356b6f6..c0b4b57 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -300,6 +300,18 @@
}
}
+/* XHCI reset, resets other CORE registers as well, re-init those */
+void dwc3_post_host_reset_core_init(struct dwc3 *dwc)
+{
+ /*
+ * XHCI reset clears EVENT buffer register as well, re-init
+ * EVENT buffers and also do device specific re-initialization
+ */
+ dwc3_event_buffers_setup(dwc);
+
+ dwc3_gadget_restart(dwc);
+}
+
static void __devinit dwc3_cache_hwparams(struct dwc3 *dwc)
{
struct dwc3_hwparams *parms = &dwc->hwparams;
@@ -572,6 +584,13 @@
goto err1;
}
+ ret = dwc3_host_init(dwc);
+ if (ret) {
+ dev_err(dev, "failed to initialize host\n");
+ dwc3_otg_exit(dwc);
+ goto err1;
+ }
+
ret = dwc3_gadget_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize gadget\n");
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 4485a43..3fb89cd 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -917,6 +917,9 @@
int dwc3_gadget_init(struct dwc3 *dwc);
void dwc3_gadget_exit(struct dwc3 *dwc);
+void dwc3_gadget_restart(struct dwc3 *dwc);
+void dwc3_post_host_reset_core_init(struct dwc3 *dwc);
+
extern int dwc3_get_device_id(void);
extern void dwc3_put_device_id(int id);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index b71bd3e..0531f83 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/pm_runtime.h>
+#include <linux/ratelimit.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/clk.h>
@@ -32,8 +33,10 @@
#include <linux/usb/gadget.h>
#include <linux/usb/msm_hsusb.h>
#include <linux/regulator/consumer.h>
+#include <linux/power_supply.h>
#include <mach/rpm-regulator.h>
+#include <mach/msm_xo.h>
#include <mach/msm_bus.h>
#include "dwc3_otg.h"
@@ -127,6 +130,7 @@
u8 ep_num_mapping[DBM_MAX_EPS];
const struct usb_ep_ops *original_ep_ops[DWC3_ENDPOINTS_NUM];
struct list_head req_complete_list;
+ struct msm_xo_voter *xo_handle;
struct clk *ref_clk;
struct clk *core_clk;
struct clk *iface_clk;
@@ -143,6 +147,8 @@
bool resume_pending;
atomic_t pm_suspended;
atomic_t in_lpm;
+ int hs_phy_irq;
+ bool lpm_irq_seen;
struct delayed_work resume_work;
struct wake_lock wlock;
struct dwc3_charger charger;
@@ -152,6 +158,11 @@
u8 dcd_retries;
u32 bus_perf_client;
struct msm_bus_scale_pdata *bus_scale_table;
+ struct power_supply usb_psy;
+ unsigned int online;
+ unsigned int host_mode;
+ unsigned int current_max;
+ bool vbus_active;
};
#define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */
@@ -615,7 +626,8 @@
params.param0 = 0; /* TDAddr High */
params.param1 = lower_32_bits(req->trb_dma); /* DAddr Low */
- cmd = DWC3_DEPCMD_STARTTRANSFER;
+ /* DBM requires IOC to be set */
+ cmd = DWC3_DEPCMD_STARTTRANSFER | DWC3_DEPCMD_CMDIOC;
ret = dwc3_send_gadget_ep_cmd(dep->dwc, dep->number, cmd, ¶ms);
if (ret < 0) {
dev_dbg(dep->dwc->dev,
@@ -1238,12 +1250,35 @@
return 0;
}
- clk_disable_unprepare(mdwc->iface_clk);
- clk_disable_unprepare(mdwc->core_clk);
+ /* Sequence to put hardware in low power state:
+ * 1. Set OTGDISABLE to disable OTG block in HSPHY (saves power)
+ * 2. Clear charger detection control fields
+ * 3. SUSPEND PHY and turn OFF core clock after some delay
+ * 4. Clear interrupt latch register and enable BSV, ID HV interrupts
+ * 5. Enable PHY retention
+ */
+ dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x1000, 0x1000);
+ dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x37, 0x0);
+ dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
+ 0xC00000, 0x800000);
+
+ usleep_range(1000, 1200);
clk_disable_unprepare(mdwc->ref_clk);
- dwc3_hsusb_ldo_enable(0);
- dwc3_ssusb_ldo_enable(0);
- wake_unlock(&mdwc->wlock);
+
+ dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0xFFF);
+ dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x18000, 0x18000);
+ dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x2, 0x0);
+
+ /* make sure above writes are completed before turning off clocks */
+ wmb();
+ clk_disable_unprepare(mdwc->core_clk);
+ clk_disable_unprepare(mdwc->iface_clk);
+
+ /* USB PHY no more requires TCXO */
+ ret = msm_xo_mode_vote(mdwc->xo_handle, MSM_XO_MODE_OFF);
+ if (ret)
+ dev_err(mdwc->dev, "%s failed to devote for TCXO buffer%d\n",
+ __func__, ret);
if (mdwc->bus_perf_client) {
ret = msm_bus_scale_client_update_request(
@@ -1252,7 +1287,13 @@
dev_err(mdwc->dev, "Failed to reset bus bw vote\n");
}
+ if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability)
+ dwc3_hsusb_ldo_enable(0);
+
+ dwc3_hsusb_config_vddcx(0);
+ wake_unlock(&mdwc->wlock);
atomic_set(&mdwc->in_lpm, 1);
+
dev_info(mdwc->dev, "DWC3 in low power mode\n");
return 0;
@@ -1269,6 +1310,8 @@
return 0;
}
+ wake_lock(&mdwc->wlock);
+
if (mdwc->bus_perf_client) {
ret = msm_bus_scale_client_update_request(
mdwc->bus_perf_client, 1);
@@ -1276,14 +1319,45 @@
dev_err(mdwc->dev, "Failed to vote for bus scaling\n");
}
- wake_lock(&mdwc->wlock);
+ /* Vote for TCXO while waking up USB HSPHY */
+ ret = msm_xo_mode_vote(mdwc->xo_handle, MSM_XO_MODE_ON);
+ if (ret)
+ dev_err(mdwc->dev, "%s failed to vote for TCXO buffer%d\n",
+ __func__, ret);
+
+ if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability)
+ dwc3_hsusb_ldo_enable(1);
+
+ dwc3_hsusb_config_vddcx(1);
clk_prepare_enable(mdwc->ref_clk);
- clk_prepare_enable(mdwc->core_clk);
+ usleep_range(1000, 1200);
+
clk_prepare_enable(mdwc->iface_clk);
- dwc3_hsusb_ldo_enable(1);
- dwc3_ssusb_ldo_enable(1);
+ clk_prepare_enable(mdwc->core_clk);
+
+ /* Disable HV interrupt */
+ dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x18000, 0x0);
+ /* Disable Retention */
+ dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x2, 0x2);
+
+ dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
+ dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) | 0xF0000000);
+ /* 20usec delay required before de-asserting PHY RESET */
+ udelay(20);
+ dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
+ dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) & 0x7FFFFFFF);
+
+ /* Bring PHY out of suspend */
+ dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0xC00000, 0x0);
atomic_set(&mdwc->in_lpm, 0);
+
+ /* match disable_irq call from isr */
+ if (mdwc->lpm_irq_seen && mdwc->hs_phy_irq) {
+ enable_irq(mdwc->hs_phy_irq);
+ mdwc->lpm_irq_seen = false;
+ }
+
dev_info(mdwc->dev, "DWC3 exited from low power mode\n");
return 0;
@@ -1313,10 +1387,13 @@
mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
DWC3_EVENT_PHY_RESUME);
pm_runtime_put_sync(mdwc->dev);
+ if (mdwc->otg_xceiv && (mdwc->ext_xceiv.otg_capability))
+ mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
+ DWC3_EVENT_XCEIV_STATE);
}
}
-static bool debug_id, debug_bsv, debug_connect;
+static u32 debug_id, debug_bsv, debug_connect;
static int dwc3_connect_show(struct seq_file *s, void *unused)
{
@@ -1386,11 +1463,11 @@
return;
if (!debugfs_create_bool("id", S_IRUGO | S_IWUSR, dwc3_debugfs_root,
- (u32 *)&debug_id))
+ &debug_id))
goto error;
if (!debugfs_create_bool("bsv", S_IRUGO | S_IWUSR, dwc3_debugfs_root,
- (u32 *)&debug_bsv))
+ &debug_bsv))
goto error;
if (!debugfs_create_file("connect", S_IRUGO | S_IWUSR,
@@ -1403,6 +1480,106 @@
debugfs_remove_recursive(dwc3_debugfs_root);
}
+static irqreturn_t msm_dwc3_irq(int irq, void *data)
+{
+ struct dwc3_msm *mdwc = data;
+
+ if (atomic_read(&mdwc->in_lpm)) {
+ dev_dbg(mdwc->dev, "%s received in LPM\n", __func__);
+ mdwc->lpm_irq_seen = true;
+ disable_irq_nosync(irq);
+ queue_delayed_work(system_nrt_wq, &mdwc->resume_work, 0);
+ } else {
+ pr_info_ratelimited("%s: IRQ outside LPM\n", __func__);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int dwc3_msm_power_get_property_usb(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct dwc3_msm *mdwc = container_of(psy, struct dwc3_msm,
+ usb_psy);
+ switch (psp) {
+ case POWER_SUPPLY_PROP_SCOPE:
+ val->intval = mdwc->host_mode;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ val->intval = mdwc->current_max;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = mdwc->vbus_active;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = mdwc->online;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int dwc3_msm_power_set_property_usb(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ static bool init;
+ struct dwc3_msm *mdwc = container_of(psy, struct dwc3_msm,
+ usb_psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_SCOPE:
+ mdwc->host_mode = val->intval;
+ break;
+ /* Process PMIC notification in PRESENT prop */
+ case POWER_SUPPLY_PROP_PRESENT:
+ dev_dbg(mdwc->dev, "%s: notify xceiv event\n", __func__);
+ if (mdwc->otg_xceiv && (mdwc->ext_xceiv.otg_capability ||
+ !init)) {
+ mdwc->ext_xceiv.bsv = val->intval;
+ mdwc->ext_xceiv.id = DWC3_ID_FLOAT;
+ if (atomic_read(&mdwc->in_lpm)) {
+ dev_dbg(mdwc->dev,
+ "%s received in LPM\n", __func__);
+ queue_delayed_work(system_nrt_wq,
+ &mdwc->resume_work, 0);
+ } else {
+ mdwc->ext_xceiv.notify_ext_events(
+ mdwc->otg_xceiv->otg,
+ DWC3_EVENT_XCEIV_STATE);
+ }
+ }
+ if (!init)
+ init = true;
+ mdwc->vbus_active = val->intval;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ mdwc->online = val->intval;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ mdwc->current_max = val->intval;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ power_supply_changed(&mdwc->usb_psy);
+ return 0;
+}
+
+static char *dwc3_msm_pm_power_supplied_to[] = {
+ "battery",
+};
+
+static enum power_supply_property dwc3_msm_pm_power_props_usb[] = {
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_SCOPE,
+};
+
static int __devinit dwc3_msm_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
@@ -1426,6 +1603,20 @@
INIT_DELAYED_WORK(&msm->chg_work, dwc3_chg_detect_work);
INIT_DELAYED_WORK(&msm->resume_work, dwc3_resume_work);
+ msm->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
+ if (IS_ERR(msm->xo_handle)) {
+ dev_err(&pdev->dev, "%s unable to get TCXO buffer handle\n",
+ __func__);
+ return PTR_ERR(msm->xo_handle);
+ }
+
+ ret = msm_xo_mode_vote(msm->xo_handle, MSM_XO_MODE_ON);
+ if (ret) {
+ dev_err(&pdev->dev, "%s failed to vote for TCXO buffer%d\n",
+ __func__, ret);
+ goto free_xo_handle;
+ }
+
/*
* DWC3 Core requires its CORE CLK (aka master / bus clk) to
* run at 125Mhz in SSUSB mode and >60MHZ for HSUSB mode.
@@ -1433,7 +1624,8 @@
msm->core_clk = devm_clk_get(&pdev->dev, "core_clk");
if (IS_ERR(msm->core_clk)) {
dev_err(&pdev->dev, "failed to get core_clk\n");
- return PTR_ERR(msm->core_clk);
+ ret = PTR_ERR(msm->core_clk);
+ goto free_xo_handle;
}
clk_set_rate(msm->core_clk, 125000000);
clk_prepare_enable(msm->core_clk);
@@ -1548,6 +1740,26 @@
goto free_hs_ldo_init;
}
+ msm->ext_xceiv.otg_capability = of_property_read_bool(node,
+ "qcom,dwc-usb3-msm-otg-capability");
+
+ if (!msm->ext_xceiv.otg_capability) {
+ /* DWC3 has separate IRQ line for OTG events (ID/BSV etc.) */
+ msm->hs_phy_irq = platform_get_irq_byname(pdev, "hs_phy_irq");
+ if (msm->hs_phy_irq < 0) {
+ dev_dbg(&pdev->dev, "pget_irq for hs_phy_irq failed\n");
+ msm->hs_phy_irq = 0;
+ } else {
+ ret = request_irq(msm->hs_phy_irq, msm_dwc3_irq,
+ IRQF_TRIGGER_RISING, "msm_dwc3", msm);
+ if (ret) {
+ dev_err(&pdev->dev, "irqreq HSPHYINT failed\n");
+ goto disable_hs_ldo;
+ }
+ enable_irq_wake(msm->hs_phy_irq);
+ }
+ }
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res) {
dev_dbg(&pdev->dev, "missing TCSR memory resource\n");
@@ -1571,7 +1783,7 @@
if (!res) {
dev_err(&pdev->dev, "missing memory base resource\n");
ret = -ENODEV;
- goto disable_hs_ldo;
+ goto free_hsphy_irq;
}
msm->base = devm_ioremap_nocache(&pdev->dev, res->start,
@@ -1579,14 +1791,14 @@
if (!msm->base) {
dev_err(&pdev->dev, "ioremap failed\n");
ret = -ENODEV;
- goto disable_hs_ldo;
+ goto free_hsphy_irq;
}
dwc3 = platform_device_alloc("dwc3", -1);
if (!dwc3) {
dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
ret = -ENODEV;
- goto disable_hs_ldo;
+ goto free_hsphy_irq;
}
dwc3->dev.parent = &pdev->dev;
@@ -1614,10 +1826,11 @@
*/
dwc3_msm_write_reg(msm->base, HS_PHY_CTRL_REG, 0x5220bb2);
usleep_range(2000, 2200);
- /* Disable (bypass) VBUS filter */
- dwc3_msm_write_reg(msm->base, QSCRATCH_GENERAL_CFG, 0x38);
+ /* Disable (bypass) VBUS and ID filters */
+ dwc3_msm_write_reg(msm->base, QSCRATCH_GENERAL_CFG, 0x78);
pm_runtime_set_active(msm->dev);
+ pm_runtime_enable(msm->dev);
if (of_property_read_u32(node, "qcom,dwc-usb3-msm-dbm-eps",
&msm->dbm_num_eps)) {
@@ -1635,17 +1848,35 @@
goto put_pdev;
}
+ msm->usb_psy.name = "usb";
+ msm->usb_psy.type = POWER_SUPPLY_TYPE_USB;
+ msm->usb_psy.supplied_to = dwc3_msm_pm_power_supplied_to;
+ msm->usb_psy.num_supplicants = ARRAY_SIZE(
+ dwc3_msm_pm_power_supplied_to);
+ msm->usb_psy.properties = dwc3_msm_pm_power_props_usb;
+ msm->usb_psy.num_properties = ARRAY_SIZE(dwc3_msm_pm_power_props_usb);
+ msm->usb_psy.get_property = dwc3_msm_power_get_property_usb;
+ msm->usb_psy.set_property = dwc3_msm_power_set_property_usb;
+
+ ret = power_supply_register(&pdev->dev, &msm->usb_psy);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "%s:power_supply_register usb failed\n",
+ __func__);
+ goto put_pdev;
+ }
+
ret = platform_device_add_resources(dwc3, pdev->resource,
pdev->num_resources);
if (ret) {
dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
- goto put_pdev;
+ goto put_psupply;
}
ret = platform_device_add(dwc3);
if (ret) {
dev_err(&pdev->dev, "failed to register dwc3 device\n");
- goto put_pdev;
+ goto put_psupply;
}
msm->bus_scale_table = msm_bus_cl_get_pdata(pdev);
@@ -1665,8 +1896,9 @@
usleep_range(1000, 1200);
dwc3_msm_dbm_soft_reset(0);
- dwc3_msm_event_buffer_config(dwc3_readl(msm->base, DWC3_GEVNTADRLO(0)),
- dwc3_readl(msm->base, DWC3_GEVNTSIZ(0)));
+ dwc3_msm_event_buffer_config(dwc3_msm_read_reg(msm->base,
+ DWC3_GEVNTADRLO(0)),
+ dwc3_msm_read_reg(msm->base, DWC3_GEVNTSIZ(0)));
msm->otg_xceiv = usb_get_transceiver();
if (msm->otg_xceiv) {
@@ -1697,8 +1929,13 @@
put_xcvr:
usb_put_transceiver(msm->otg_xceiv);
platform_device_del(dwc3);
+put_psupply:
+ power_supply_unregister(&msm->usb_psy);
put_pdev:
platform_device_put(dwc3);
+free_hsphy_irq:
+ if (msm->hs_phy_irq)
+ free_irq(msm->hs_phy_irq, msm);
disable_hs_ldo:
dwc3_hsusb_ldo_enable(0);
free_hs_ldo_init:
@@ -1725,6 +1962,8 @@
clk_disable_unprepare(msm->iface_clk);
disable_core_clk:
clk_disable_unprepare(msm->core_clk);
+free_xo_handle:
+ msm_xo_put(msm->xo_handle);
return ret;
}
@@ -1756,6 +1995,7 @@
clk_disable_unprepare(msm->sleep_clk);
clk_disable_unprepare(msm->hsphy_sleep_clk);
clk_disable_unprepare(msm->ref_clk);
+ msm_xo_put(msm->xo_handle);
return 0;
}
@@ -1792,9 +2032,14 @@
pm_runtime_enable(dev);
/* Let OTG know about resume event and update pm_count */
- if (mdwc->otg_xceiv)
+ if (mdwc->otg_xceiv) {
mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
DWC3_EVENT_PHY_RESUME);
+ if (mdwc->ext_xceiv.otg_capability)
+ mdwc->ext_xceiv.notify_ext_events(
+ mdwc->otg_xceiv->otg,
+ DWC3_EVENT_XCEIV_STATE);
+ }
}
return ret;
@@ -1849,7 +2094,7 @@
},
};
-MODULE_LICENSE("GPLV2");
+MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("DesignWare USB3 MSM Glue Layer");
static int __devinit dwc3_msm_init(void)
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index 4a37f03..1aa8519 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -16,12 +16,17 @@
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
#include "core.h"
#include "dwc3_otg.h"
#include "io.h"
#include "xhci.h"
+static void dwc3_otg_reset(struct dwc3_otg *dotg);
+
+static void dwc3_otg_notify_host_mode(struct usb_otg *otg, int host_mode);
+static void dwc3_otg_reset(struct dwc3_otg *dotg);
/**
* dwc3_otg_set_host_regs - reset dwc3 otg registers to host operation.
@@ -29,7 +34,7 @@
* This function sets the OTG registers to work in A-Device host mode.
* This function should be called just before entering to A-Device mode.
*
- * @w: Pointer to the dwc3 otg workqueue.
+ * @w: Pointer to the dwc3 otg struct
*/
static void dwc3_otg_set_host_regs(struct dwc3_otg *dotg)
{
@@ -39,11 +44,26 @@
octl = dwc3_readl(dotg->regs, DWC3_OCTL);
octl &= ~DWC3_OTG_OCTL_PERIMODE;
dwc3_writel(dotg->regs, DWC3_OCTL, octl);
+}
- /*
- * TODO: add more OTG registers writes for HOST mode here,
- * see figure 12-10 A-device flow in dwc3 Synopsis spec
- */
+/**
+ * dwc3_otg_set_host_power - Enable port power control for host operation
+ *
+ * This function enables the OTG Port Power required to operate in Host mode
+ * This function should be called only after XHCI driver has set the port
+ * power in PORTSC register.
+ *
+ * @w: Pointer to the dwc3 otg struct
+ */
+void dwc3_otg_set_host_power(struct dwc3_otg *dotg)
+{
+ u32 osts;
+
+ osts = dwc3_readl(dotg->regs, DWC3_OSTS);
+ if (!(osts & 0x8))
+ dev_err(dotg->dwc->dev, "%s: xHCIPrtPower not set\n", __func__);
+
+ dwc3_writel(dotg->regs, DWC3_OCTL, DWC3_OTG_OCTL_PRTPWRCTL);
}
/**
@@ -80,19 +100,13 @@
static int dwc3_otg_start_host(struct usb_otg *otg, int on)
{
struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
- struct usb_hcd *hcd;
- struct xhci_hcd *xhci;
int ret = 0;
- if (!otg->host)
+ if (!dotg->dwc->xhci)
return -EINVAL;
- hcd = bus_to_hcd(otg->host);
- xhci = hcd_to_xhci(hcd);
if (on) {
- dev_dbg(otg->phy->dev, "%s: turn on host %s\n",
- __func__, otg->host->bus_name);
- dwc3_otg_set_host_regs(dotg);
+ dev_dbg(otg->phy->dev, "%s: turn on host\n", __func__);
/*
* This should be revisited for more testing post-silicon.
@@ -104,25 +118,40 @@
* remove_hcd, But we may not use standard set_host method
* anymore.
*/
- ret = hcd->driver->start(hcd);
+ dwc3_otg_set_host_regs(dotg);
+ ret = platform_device_add(dotg->dwc->xhci);
if (ret) {
dev_err(otg->phy->dev,
- "%s: failed to start primary hcd, ret=%d\n",
+ "%s: failed to add XHCI pdev ret=%d\n",
__func__, ret);
return ret;
}
- ret = xhci->shared_hcd->driver->start(xhci->shared_hcd);
+ dwc3_otg_notify_host_mode(otg, on);
+ ret = regulator_enable(dotg->vbus_otg);
if (ret) {
- dev_err(otg->phy->dev,
- "%s: failed to start secondary hcd, ret=%d\n",
- __func__, ret);
+ dev_err(otg->phy->dev, "unable to enable vbus_otg\n");
+ platform_device_del(dotg->dwc->xhci);
return ret;
}
+
+ /* re-init OTG EVTEN register as XHCI reset clears it */
+ dwc3_otg_reset(dotg);
} else {
- dev_dbg(otg->phy->dev, "%s: turn off host %s\n",
- __func__, otg->host->bus_name);
- hcd->driver->stop(hcd);
+ dev_dbg(otg->phy->dev, "%s: turn off host\n", __func__);
+
+ platform_device_del(dotg->dwc->xhci);
+
+ ret = regulator_disable(dotg->vbus_otg);
+ if (ret) {
+ dev_err(otg->phy->dev, "unable to disable vbus_otg\n");
+ return ret;
+ }
+ dwc3_otg_notify_host_mode(otg, on);
+
+ /* re-init core and OTG register as XHCI reset clears it */
+ dwc3_post_host_reset_core_init(dotg->dwc);
+ dwc3_otg_reset(dotg);
}
return 0;
@@ -141,26 +170,18 @@
struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
if (host) {
- dev_dbg(otg->phy->dev, "%s: set host %s\n",
+ dev_dbg(otg->phy->dev, "%s: set host %s, portpower\n",
__func__, host->bus_name);
otg->host = host;
-
/*
- * Only after both peripheral and host are set then check
- * OTG sm. This prevents unnecessary activation of the sm
- * in case the ID is high.
+ * Though XHCI power would be set by now, but some delay is
+ * required for XHCI controller before setting OTG Port Power
+ * TODO: Tune this delay
*/
- if (otg->gadget)
- schedule_work(&dotg->sm_work);
+ msleep(300);
+ dwc3_otg_set_host_power(dotg);
} else {
- if (otg->phy->state == OTG_STATE_A_HOST) {
- dwc3_otg_start_host(otg, 0);
- otg->host = NULL;
- otg->phy->state = OTG_STATE_UNDEFINED;
- schedule_work(&dotg->sm_work);
- } else {
- otg->host = NULL;
- }
+ otg->host = NULL;
}
return 0;
@@ -212,14 +233,7 @@
dev_dbg(otg->phy->dev, "%s: set gadget %s\n",
__func__, gadget->name);
otg->gadget = gadget;
-
- /*
- * Only after both peripheral and host are set then check
- * OTG sm. This prevents unnecessary activation of the sm
- * in case the ID is grounded.
- */
- if (otg->host)
- schedule_work(&dotg->sm_work);
+ schedule_work(&dotg->sm_work);
} else {
if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
dwc3_otg_start_peripheral(otg, 0);
@@ -281,9 +295,11 @@
static void dwc3_ext_event_notify(struct usb_otg *otg,
enum dwc3_ext_events event)
{
+ static bool init;
struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv;
struct usb_phy *phy = dotg->otg.phy;
+ int ret = 0;
if (event == DWC3_EVENT_PHY_RESUME) {
if (!pm_runtime_status_suspended(phy->dev)) {
@@ -291,21 +307,39 @@
} else {
dev_dbg(phy->dev, "ext PHY_RESUME event received\n");
/* ext_xceiver would have taken h/w out of LPM by now */
- pm_runtime_get(phy->dev);
+ ret = pm_runtime_get(phy->dev);
+ if (ret == -EACCES) {
+ /* pm_runtime_get may fail during system
+ resume with -EACCES error */
+ pm_runtime_disable(phy->dev);
+ pm_runtime_set_active(phy->dev);
+ pm_runtime_enable(phy->dev);
+ } else if (ret < 0) {
+ dev_warn(phy->dev, "pm_runtime_get failed!\n");
+ }
}
+ } else if (event == DWC3_EVENT_XCEIV_STATE) {
+ if (ext_xceiv->id == DWC3_ID_FLOAT)
+ set_bit(ID, &dotg->inputs);
+ else
+ clear_bit(ID, &dotg->inputs);
+
+ if (ext_xceiv->bsv) {
+ dev_dbg(phy->dev, "XCVR: BSV set\n");
+ set_bit(B_SESS_VLD, &dotg->inputs);
+ } else {
+ dev_dbg(phy->dev, "XCVR: BSV clear\n");
+ clear_bit(B_SESS_VLD, &dotg->inputs);
+ }
+
+ if (!init) {
+ init = true;
+ complete(&dotg->dwc3_xcvr_vbus_init);
+ dev_dbg(phy->dev, "XCVR: BSV init complete\n");
+ return;
+ }
+ schedule_work(&dotg->sm_work);
}
-
- if (ext_xceiv->id == DWC3_ID_FLOAT)
- set_bit(ID, &dotg->inputs);
- else
- clear_bit(ID, &dotg->inputs);
-
- if (ext_xceiv->bsv)
- set_bit(B_SESS_VLD, &dotg->inputs);
- else
- clear_bit(B_SESS_VLD, &dotg->inputs);
-
- schedule_work(&dotg->sm_work);
}
/**
@@ -326,6 +360,72 @@
return 0;
}
+static void dwc3_otg_notify_host_mode(struct usb_otg *otg, int host_mode)
+{
+ struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+
+ if (!dotg->psy) {
+ dev_err(otg->phy->dev, "no usb power supply registered\n");
+ return;
+ }
+
+ if (host_mode)
+ power_supply_set_scope(dotg->psy, POWER_SUPPLY_SCOPE_SYSTEM);
+ else
+ power_supply_set_scope(dotg->psy, POWER_SUPPLY_SCOPE_DEVICE);
+}
+
+static int dwc3_otg_set_power(struct usb_phy *phy, unsigned mA)
+{
+ static int power_supply_type;
+ struct dwc3_otg *dotg = container_of(phy->otg, struct dwc3_otg, otg);
+
+
+ if (!dotg->psy) {
+ dev_err(phy->dev, "no usb power supply registered\n");
+ return 0;
+ }
+
+ if (dotg->charger->chg_type == DWC3_SDP_CHARGER)
+ power_supply_type = POWER_SUPPLY_TYPE_USB;
+ else if (dotg->charger->chg_type == DWC3_CDP_CHARGER)
+ power_supply_type = POWER_SUPPLY_TYPE_USB_CDP;
+ else if (dotg->charger->chg_type == DWC3_DCP_CHARGER)
+ power_supply_type = POWER_SUPPLY_TYPE_USB_DCP;
+ else
+ power_supply_type = POWER_SUPPLY_TYPE_BATTERY;
+
+ power_supply_set_supply_type(dotg->psy, power_supply_type);
+
+ if (dotg->charger->max_power == mA)
+ return 0;
+
+ dev_info(phy->dev, "Avail curr from USB = %u\n", mA);
+
+ if (dotg->charger->max_power <= 2 && mA > 2) {
+ /* Enable charging */
+ if (power_supply_set_online(dotg->psy, true))
+ goto psy_error;
+ if (power_supply_set_current_limit(dotg->psy, 1000*mA))
+ goto psy_error;
+ } else if (dotg->charger->max_power > 0 && (mA == 0 || mA == 2)) {
+ /* Disable charging */
+ if (power_supply_set_online(dotg->psy, false))
+ goto psy_error;
+ /* Set max current limit */
+ if (power_supply_set_current_limit(dotg->psy, 0))
+ goto psy_error;
+ }
+
+ power_supply_changed(dotg->psy);
+ dotg->charger->max_power = mA;
+ return 0;
+
+psy_error:
+ dev_dbg(phy->dev, "power supply error when setting property\n");
+ return -ENXIO;
+}
+
/* IRQs which OTG driver is interested in handling */
#define DWC3_OEVT_MASK (DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT | \
DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT)
@@ -339,21 +439,10 @@
static irqreturn_t dwc3_otg_interrupt(int irq, void *_dotg)
{
struct dwc3_otg *dotg = (struct dwc3_otg *)_dotg;
- struct usb_phy *phy = dotg->otg.phy;
u32 osts, oevt_reg;
int ret = IRQ_NONE;
int handled_irqs = 0;
- /*
- * If PHY is in retention mode then this interrupt would not be fired.
- * ext_xcvr (parent) is responsible for bringing h/w out of LPM.
- * OTG driver just need to increment power count and can safely
- * assume that h/w is out of low power state now.
- * TODO: explicitly disable OEVTEN interrupts if ext_xceiv is present
- */
- if (pm_runtime_status_suspended(phy->dev))
- pm_runtime_get(phy->dev);
-
oevt_reg = dwc3_readl(dotg->regs, DWC3_OEVT);
if (!(oevt_reg & DWC3_OEVT_MASK))
@@ -403,23 +492,32 @@
{
u32 osts = dwc3_readl(dotg->regs, DWC3_OSTS);
struct usb_phy *phy = dotg->otg.phy;
-
- /*
- * TODO: If using external notifications then wait here till initial
- * state is reported
- */
+ struct dwc3_ext_xceiv *ext_xceiv;
+ int ret;
dev_dbg(phy->dev, "Initialize OTG inputs, osts: 0x%x\n", osts);
- if (osts & DWC3_OTG_OSTS_CONIDSTS)
- set_bit(ID, &dotg->inputs);
- else
- clear_bit(ID, &dotg->inputs);
+ /*
+ * VBUS initial state is reported after PMIC
+ * driver initialization. Wait for it.
+ */
+ ret = wait_for_completion_timeout(&dotg->dwc3_xcvr_vbus_init, HZ * 5);
+ if (!ret)
+ dev_err(phy->dev, "%s: completion timeout\n", __func__);
- if (osts & DWC3_OTG_OSTS_BSESVALID)
- set_bit(B_SESS_VLD, &dotg->inputs);
- else
- clear_bit(B_SESS_VLD, &dotg->inputs);
+ ext_xceiv = dotg->ext_xceiv;
+ dwc3_otg_reset(dotg);
+ if (ext_xceiv && !ext_xceiv->otg_capability) {
+ if (osts & DWC3_OTG_OSTS_CONIDSTS)
+ set_bit(ID, &dotg->inputs);
+ else
+ clear_bit(ID, &dotg->inputs);
+
+ if (osts & DWC3_OTG_OSTS_BSESVALID)
+ set_bit(B_SESS_VLD, &dotg->inputs);
+ else
+ clear_bit(B_SESS_VLD, &dotg->inputs);
+ }
}
/**
@@ -444,8 +542,16 @@
switch (phy->state) {
case OTG_STATE_UNDEFINED:
dwc3_otg_init_sm(dotg);
+ if (!dotg->psy) {
+ dotg->psy = power_supply_get_by_name("usb");
+
+ if (!dotg->psy)
+ dev_err(phy->dev,
+ "couldn't get usb power supply\n");
+ }
+
/* Switch to A or B-Device according to ID / BSV */
- if (!test_bit(ID, &dotg->inputs) && phy->otg->host) {
+ if (!test_bit(ID, &dotg->inputs)) {
dev_dbg(phy->dev, "!id\n");
phy->state = OTG_STATE_A_IDLE;
work = 1;
@@ -461,7 +567,7 @@
break;
case OTG_STATE_B_IDLE:
- if (!test_bit(ID, &dotg->inputs) && phy->otg->host) {
+ if (!test_bit(ID, &dotg->inputs)) {
dev_dbg(phy->dev, "!id\n");
phy->state = OTG_STATE_A_IDLE;
work = 1;
@@ -480,9 +586,13 @@
switch (charger->chg_type) {
case DWC3_DCP_CHARGER:
dev_dbg(phy->dev, "lpm, DCP charger\n");
+ dwc3_otg_set_power(phy,
+ DWC3_IDEV_CHG_MAX);
pm_runtime_put_sync(phy->dev);
break;
case DWC3_CDP_CHARGER:
+ dwc3_otg_set_power(phy,
+ DWC3_IDEV_CHG_MAX);
dwc3_otg_start_peripheral(&dotg->otg,
1);
phy->state = OTG_STATE_B_PERIPHERAL;
@@ -523,6 +633,7 @@
charger->chg_type =
DWC3_INVALID_CHARGER;
}
+ dwc3_otg_set_power(phy, 0);
dev_dbg(phy->dev, "No device, trying to suspend\n");
pm_runtime_put_sync(phy->dev);
}
@@ -588,6 +699,9 @@
*/
static void dwc3_otg_reset(struct dwc3_otg *dotg)
{
+ static int once;
+ struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv;
+
/*
* OCFG[2] - OTG-Version = 1
* OCFG[1] - HNPCap = 0
@@ -604,15 +718,19 @@
* OCTL[1] - DevSetHNPEn = 0
* OCTL[0] - HstSetHNPEn = 0
*/
- dwc3_writel(dotg->regs, DWC3_OCTL, 0x40);
+ if (!once) {
+ dwc3_writel(dotg->regs, DWC3_OCTL, 0x40);
+ once++;
+ }
/* Clear all otg events (interrupts) indications */
dwc3_writel(dotg->regs, DWC3_OEVT, 0xFFFF);
/* Enable ID/BSV StsChngEn event*/
- dwc3_writel(dotg->regs, DWC3_OEVTEN,
- DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT |
- DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT);
+ if (ext_xceiv && !ext_xceiv->otg_capability)
+ dwc3_writel(dotg->regs, DWC3_OEVTEN,
+ DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT |
+ DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT);
}
/**
@@ -651,6 +769,13 @@
return -ENOMEM;
}
+ dotg->vbus_otg = devm_regulator_get(dwc->dev->parent, "vbus_dwc3");
+ if (IS_ERR(dotg->vbus_otg)) {
+ dev_err(dwc->dev, "Unable to get vbus_dwc3 regulator\n");
+ ret = PTR_ERR(dotg->vbus_otg);
+ goto err1;
+ }
+
/* DWC3 has separate IRQ line for OTG events (ID/BSV etc.) */
dotg->irq = platform_get_irq_byname(to_platform_device(dwc->dev),
"otg_irq");
@@ -675,8 +800,10 @@
goto err1;
}
+ dotg->dwc = dwc;
dotg->otg.phy->otg = &dotg->otg;
dotg->otg.phy->dev = dwc->dev;
+ dotg->otg.phy->set_power = dwc3_otg_set_power;
ret = usb_set_transceiver(dotg->otg.phy);
if (ret) {
@@ -686,10 +813,9 @@
goto err2;
}
- dwc3_otg_reset(dotg);
-
dotg->otg.phy->state = OTG_STATE_UNDEFINED;
+ init_completion(&dotg->dwc3_xcvr_vbus_init);
INIT_WORK(&dotg->sm_work, dwc3_otg_sm_work);
ret = request_irq(dotg->irq, dwc3_otg_interrupt, IRQF_SHARED,
diff --git a/drivers/usb/dwc3/dwc3_otg.h b/drivers/usb/dwc3/dwc3_otg.h
index b60b42a..4384888 100644
--- a/drivers/usb/dwc3/dwc3_otg.h
+++ b/drivers/usb/dwc3/dwc3_otg.h
@@ -17,9 +17,12 @@
#define __LINUX_USB_DWC3_OTG_H
#include <linux/workqueue.h>
+#include <linux/power_supply.h>
#include <linux/usb/otg.h>
+#define DWC3_IDEV_CHG_MAX 1500
+
struct dwc3_charger;
/**
@@ -32,15 +35,19 @@
* @inputs: OTG state machine inputs
*/
struct dwc3_otg {
- struct usb_otg otg;
- int irq;
- void __iomem *regs;
+ struct usb_otg otg;
+ int irq;
+ struct dwc3 *dwc;
+ void __iomem *regs;
+ struct regulator *vbus_otg;
struct work_struct sm_work;
struct dwc3_charger *charger;
struct dwc3_ext_xceiv *ext_xceiv;
#define ID 0
#define B_SESS_VLD 1
unsigned long inputs;
+ struct power_supply *psy;
+ struct completion dwc3_xcvr_vbus_init;
};
/**
@@ -62,6 +69,7 @@
struct dwc3_charger {
enum dwc3_chg_type chg_type;
+ unsigned max_power;
/* start/stop charger detection, provided by external charger module */
void (*start_detection)(struct dwc3_charger *charger, bool start);
@@ -89,6 +97,7 @@
struct dwc3_ext_xceiv {
enum dwc3_id_state id;
bool bsv;
+ bool otg_capability;
/* to notify OTG about LPM exit event, provided by OTG */
void (*notify_ext_events)(struct usb_otg *otg,
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 9b1576b..9c1ebf8 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1455,6 +1455,17 @@
return 0;
}
+static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned mA)
+{
+ struct dwc3 *dwc = gadget_to_dwc(g);
+ struct dwc3_otg *dotg = dwc->dotg;
+
+ if (dotg && dotg->otg.phy)
+ return usb_phy_set_power(dotg->otg.phy, mA);
+
+ return -ENOTSUPP;
+}
+
static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
{
struct dwc3 *dwc = gadget_to_dwc(g);
@@ -1523,6 +1534,37 @@
return ret;
}
+/* Required gadget re-initialization before switching to gadget in OTG mode */
+void dwc3_gadget_restart(struct dwc3 *dwc)
+{
+ struct dwc3_ep *dep;
+ int ret = 0;
+
+ /* reinitialize physical ep0-1 */
+
+ dwc->delayed_status = false;
+
+ dep = dwc->eps[0];
+ dep->flags = 0;
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
+ if (ret) {
+ dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+ return;
+ }
+
+ dep = dwc->eps[1];
+ dep->flags = 0;
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
+ if (ret) {
+ dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+ return;
+ }
+
+ /* begin to receive SETUP packets */
+ dwc->ep0state = EP0_SETUP_PHASE;
+ dwc3_ep0_out_start(dwc);
+}
+
static int dwc3_gadget_start(struct usb_gadget *g,
struct usb_gadget_driver *driver)
{
@@ -1627,6 +1669,7 @@
.wakeup = dwc3_gadget_wakeup,
.set_selfpowered = dwc3_gadget_set_selfpowered,
.vbus_session = dwc3_gadget_vbus_session,
+ .vbus_draw = dwc3_gadget_vbus_draw,
.pullup = dwc3_gadget_pullup,
.udc_start = dwc3_gadget_start,
.udc_stop = dwc3_gadget_stop,
@@ -2052,6 +2095,7 @@
static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
{
u32 reg;
+ struct dwc3_otg *dotg = dwc->dotg;
dev_vdbg(dwc->dev, "%s\n", __func__);
@@ -2096,6 +2140,9 @@
dwc3_gadget_usb3_phy_suspend(dwc, false);
}
+ if (dotg && dotg->otg.phy)
+ usb_phy_set_power(dotg->otg.phy, 0);
+
if (dwc->gadget.speed != USB_SPEED_UNKNOWN)
dwc3_disconnect_gadget(dwc);
@@ -2303,6 +2350,13 @@
}
}
+ if (next == DWC3_LINK_STATE_U0) {
+ if (dwc->link_state == DWC3_LINK_STATE_U3)
+ dwc->gadget_driver->resume(&dwc->gadget);
+ } else if (next == DWC3_LINK_STATE_U3) {
+ dwc->gadget_driver->suspend(&dwc->gadget);
+ }
+
dwc->link_state = next;
dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index 099708b..644a779 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -78,10 +78,13 @@
goto err1;
}
- ret = platform_device_add(xhci);
- if (ret) {
- dev_err(dwc->dev, "failed to register xHCI device\n");
- goto err1;
+ /* Add XHCI device if !OTG, otherwise OTG takes care of this */
+ if (!dwc->dotg) {
+ ret = platform_device_add(xhci);
+ if (ret) {
+ dev_err(dwc->dev, "failed to register xHCI device\n");
+ goto err1;
+ }
}
return 0;
@@ -95,5 +98,6 @@
void dwc3_host_exit(struct dwc3 *dwc)
{
- platform_device_unregister(dwc->xhci);
+ if (!dwc->dotg)
+ platform_device_unregister(dwc->xhci);
}
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index fa1bf43..9c7b1ec 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -75,7 +75,7 @@
*****************************************************************************/
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-#define ATDTW_SET_DELAY 100 /* 100msec delay */
+#define USB_MAX_TIMEOUT 100 /* 100msec timeout */
#define EP_PRIME_CHECK_DELAY (jiffies + msecs_to_jiffies(1000))
#define MAX_PRIME_CHECK_RETRY 3 /*Wait for 3sec for EP prime failure */
@@ -177,7 +177,8 @@
/* maximum number of enpoints: valid only after hw_device_reset() */
static unsigned hw_ep_max;
-
+static void dbg_usb_op_fail(u8 addr, const char *name,
+ const struct ci13xxx_ep *mep);
/**
* hw_ep_bit: calculates the bit number
* @num: endpoint number
@@ -381,6 +382,27 @@
return 0;
}
+static void debug_ept_flush_info(int ep_num, int dir)
+{
+ struct ci13xxx *udc = _udc;
+ struct ci13xxx_ep *mep;
+
+ if (dir)
+ mep = &udc->ci13xxx_ep[ep_num + hw_ep_max/2];
+ else
+ mep = &udc->ci13xxx_ep[ep_num];
+
+ pr_err_ratelimited("USB Registers\n");
+ pr_err_ratelimited("USBCMD:%x\n", hw_cread(CAP_USBCMD, ~0));
+ pr_err_ratelimited("USBSTS:%x\n", hw_cread(CAP_USBSTS, ~0));
+ pr_err_ratelimited("ENDPTLISTADDR:%x\n",
+ hw_cread(CAP_ENDPTLISTADDR, ~0));
+ pr_err_ratelimited("PORTSC:%x\n", hw_cread(CAP_PORTSC, ~0));
+ pr_err_ratelimited("USBMODE:%x\n", hw_cread(CAP_USBMODE, ~0));
+ pr_err_ratelimited("ENDPTSTAT:%x\n", hw_cread(CAP_ENDPTSTAT, ~0));
+
+ dbg_usb_op_fail(0xFF, "FLUSHF", mep);
+}
/**
* hw_ep_flush: flush endpoint fifo (execute without interruption)
* @num: endpoint number
@@ -390,13 +412,25 @@
*/
static int hw_ep_flush(int num, int dir)
{
+ ktime_t start, diff;
int n = hw_ep_bit(num, dir);
+ start = ktime_get();
do {
/* flush any pending transfer */
hw_cwrite(CAP_ENDPTFLUSH, BIT(n), BIT(n));
- while (hw_cread(CAP_ENDPTFLUSH, BIT(n)))
+ while (hw_cread(CAP_ENDPTFLUSH, BIT(n))) {
cpu_relax();
+ diff = ktime_sub(ktime_get(), start);
+ if (ktime_to_ms(diff) > USB_MAX_TIMEOUT) {
+ printk_ratelimited(KERN_ERR
+ "%s: Failed to flush ep#%d %s\n",
+ __func__, num,
+ dir ? "IN" : "OUT");
+ debug_ept_flush_info(num, dir);
+ return 0;
+ }
+ }
} while (hw_cread(CAP_ENDPTSTAT, BIT(n)));
return 0;
@@ -1006,29 +1040,30 @@
}
/**
- * dbg_prime_fail: prints a PRIME FAIL event
+ * dbg_usb_op_fail: prints USB Operation FAIL event
* @addr: endpoint address
* @mEp: endpoint structure
*/
-static void dbg_prime_fail(u8 addr, const char *name,
- const struct ci13xxx_ep *mEp)
+static void dbg_usb_op_fail(u8 addr, const char *name,
+ const struct ci13xxx_ep *mep)
{
char msg[DBG_DATA_MSG];
struct ci13xxx_req *req;
struct list_head *ptr = NULL;
- if (mEp != NULL) {
+ if (mep != NULL) {
scnprintf(msg, sizeof(msg),
- "PRIME fail EP%d%s QH:%08X",
- mEp->num, mEp->dir ? "IN" : "OUT", mEp->qh.ptr->cap);
+ "%s Fail EP%d%s QH:%08X",
+ name, mep->num,
+ mep->dir ? "IN" : "OUT", mep->qh.ptr->cap);
dbg_print(addr, name, 0, msg);
scnprintf(msg, sizeof(msg),
"cap:%08X %08X %08X\n",
- mEp->qh.ptr->curr, mEp->qh.ptr->td.next,
- mEp->qh.ptr->td.token);
+ mep->qh.ptr->curr, mep->qh.ptr->td.next,
+ mep->qh.ptr->td.token);
dbg_print(addr, "QHEAD", 0, msg);
- list_for_each(ptr, &mEp->qh.queue) {
+ list_for_each(ptr, &mep->qh.queue) {
req = list_entry(ptr, struct ci13xxx_req, queue);
scnprintf(msg, sizeof(msg),
"%08X:%08X:%08X\n",
@@ -1703,52 +1738,52 @@
static void ep_prime_timer_func(unsigned long data)
{
- struct ci13xxx_ep *mEp = (struct ci13xxx_ep *)data;
+ struct ci13xxx_ep *mep = (struct ci13xxx_ep *)data;
struct ci13xxx_req *req;
struct list_head *ptr = NULL;
- int n = hw_ep_bit(mEp->num, mEp->dir);
+ int n = hw_ep_bit(mep->num, mep->dir);
unsigned long flags;
- spin_lock_irqsave(mEp->lock, flags);
+ spin_lock_irqsave(mep->lock, flags);
if (!hw_cread(CAP_ENDPTPRIME, BIT(n)))
goto out;
- if (list_empty(&mEp->qh.queue))
+ if (list_empty(&mep->qh.queue))
goto out;
- req = list_entry(mEp->qh.queue.next, struct ci13xxx_req, queue);
+ req = list_entry(mep->qh.queue.next, struct ci13xxx_req, queue);
mb();
if (!(TD_STATUS_ACTIVE & req->ptr->token))
goto out;
- mEp->prime_timer_count++;
- if (mEp->prime_timer_count == MAX_PRIME_CHECK_RETRY) {
- mEp->prime_timer_count = 0;
+ mep->prime_timer_count++;
+ if (mep->prime_timer_count == MAX_PRIME_CHECK_RETRY) {
+ mep->prime_timer_count = 0;
pr_info("ep%d dir:%s QH:cap:%08x cur:%08x next:%08x tkn:%08x\n",
- mEp->num, mEp->dir ? "IN" : "OUT",
- mEp->qh.ptr->cap, mEp->qh.ptr->curr,
- mEp->qh.ptr->td.next, mEp->qh.ptr->td.token);
- list_for_each(ptr, &mEp->qh.queue) {
+ mep->num, mep->dir ? "IN" : "OUT",
+ mep->qh.ptr->cap, mep->qh.ptr->curr,
+ mep->qh.ptr->td.next, mep->qh.ptr->td.token);
+ list_for_each(ptr, &mep->qh.queue) {
req = list_entry(ptr, struct ci13xxx_req, queue);
pr_info("\treq:%08xnext:%08xtkn:%08xpage0:%08xsts:%d\n",
req->dma, req->ptr->next,
req->ptr->token, req->ptr->page[0],
req->req.status);
}
- dbg_prime_fail(0xFF, "PRIMEF", mEp);
- mEp->prime_fail_count++;
+ dbg_usb_op_fail(0xFF, "PRIMEF", mep);
+ mep->prime_fail_count++;
} else {
- mod_timer(&mEp->prime_timer, EP_PRIME_CHECK_DELAY);
+ mod_timer(&mep->prime_timer, EP_PRIME_CHECK_DELAY);
}
- spin_unlock_irqrestore(mEp->lock, flags);
+ spin_unlock_irqrestore(mep->lock, flags);
return;
out:
- mEp->prime_timer_count = 0;
- spin_unlock_irqrestore(mEp->lock, flags);
+ mep->prime_timer_count = 0;
+ spin_unlock_irqrestore(mep->lock, flags);
}
@@ -1874,7 +1909,7 @@
tmp_stat = hw_cread(CAP_ENDPTSTAT, BIT(n));
diff = ktime_sub(ktime_get(), start);
/* poll for max. 100ms */
- if (ktime_to_ms(diff) > ATDTW_SET_DELAY) {
+ if (ktime_to_ms(diff) > USB_MAX_TIMEOUT) {
if (hw_cread(CAP_USBCMD, USBCMD_ATDTW))
break;
printk_ratelimited(KERN_ERR
diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c
index 7966a79..14e5b60 100644
--- a/drivers/usb/gadget/f_adb.c
+++ b/drivers/usb/gadget/f_adb.c
@@ -56,6 +56,7 @@
struct usb_request *rx_req;
int rx_done;
bool notify_close;
+ bool close_notified;
};
static struct usb_interface_descriptor adb_interface_desc = {
@@ -424,8 +425,10 @@
/* clear the error latch */
atomic_set(&_adb_dev->error, 0);
- if (_adb_dev->notify_close)
+ if (_adb_dev->close_notified) {
+ _adb_dev->close_notified = false;
adb_ready_callback();
+ }
_adb_dev->notify_close = true;
return 0;
@@ -443,8 +446,10 @@
* undesired. We want to force bus reset only for certain
* commands like "adb root" and "adb usb".
*/
- if (_adb_dev->notify_close)
+ if (_adb_dev->notify_close) {
adb_closed_callback();
+ _adb_dev->close_notified = true;
+ }
adb_unlock(&_adb_dev->open_excl);
return 0;
@@ -625,7 +630,9 @@
atomic_set(&dev->open_excl, 0);
atomic_set(&dev->read_excl, 0);
atomic_set(&dev->write_excl, 0);
- dev->notify_close = true;
+
+ /* config is disabled by default if adb is present. */
+ dev->close_notified = true;
INIT_LIST_HEAD(&dev->tx_idle);
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 681435a..729910d 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -541,9 +541,7 @@
unsigned long flags;
int ret;
- int notif_c = 0;
-
- pr_info("dev:%p portno#%d\n", dev, dev->port_num);
+ pr_debug("dev:%p portno#%d\n", dev, dev->port_num);
spin_lock_irqsave(&dev->lock, flags);
@@ -565,8 +563,12 @@
return;
}
- notif_c = atomic_inc_return(&dev->not_port.notify_count);
- pr_info("atomic_inc_return[notif_c] = %d", notif_c);
+ if (atomic_inc_return(&dev->not_port.notify_count) != 1) {
+ pr_debug("delay ep_queue: notifications queue is busy[%d]",
+ atomic_read(&dev->not_port.notify_count));
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return;
+ }
event = req->buf;
event->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
@@ -577,8 +579,6 @@
event->wLength = cpu_to_le16(0);
spin_unlock_irqrestore(&dev->lock, flags);
- pr_info("Call usb_ep_queue");
-
ret = usb_ep_queue(dev->not_port.notify,
dev->not_port.notify_req, GFP_ATOMIC);
if (ret) {
@@ -586,7 +586,7 @@
pr_err("ep enqueue error %d\n", ret);
}
- pr_info("Succcessfull Exit");
+ pr_debug("Successful Exit");
}
static int
@@ -672,7 +672,6 @@
mbim->ntb_input_size = NTB_DEFAULT_IN_SIZE;
- atomic_set(&mbim->not_port.notify_count, 0);
atomic_set(&mbim->online, 0);
}
@@ -750,6 +749,21 @@
switch (mbim->not_port.notify_state) {
case NCM_NOTIFY_NONE:
+ pr_debug("Notification %02x sent\n", event->bNotificationType);
+
+ if (atomic_read(&mbim->not_port.notify_count) <= 0) {
+ pr_debug("notify_none: done");
+ return;
+ }
+
+ spin_unlock(&mbim->lock);
+ status = usb_ep_queue(mbim->not_port.notify, req, GFP_ATOMIC);
+ spin_lock(&mbim->lock);
+ if (status) {
+ atomic_dec(&mbim->not_port.notify_count);
+ pr_err("Queue notify request failed, err: %d", status);
+ }
+
return;
case NCM_NOTIFY_CONNECT:
@@ -782,20 +796,22 @@
mbim->not_port.notify_state = NCM_NOTIFY_CONNECT;
break;
}
+
event->bmRequestType = 0xA1;
event->wIndex = cpu_to_le16(mbim->ctrl_id);
- mbim->not_port.notify_req = NULL;
/*
* In double buffering if there is a space in FIFO,
* completion callback can be called right after the call,
* so unlocking
*/
+ atomic_inc(&mbim->not_port.notify_count);
+ pr_debug("queue request: notify_count = %d",
+ atomic_read(&mbim->not_port.notify_count));
spin_unlock(&mbim->lock);
status = usb_ep_queue(mbim->not_port.notify, req, GFP_ATOMIC);
spin_lock(&mbim->lock);
- if (status < 0) {
- mbim->not_port.notify_req = req;
+ if (status) {
atomic_dec(&mbim->not_port.notify_count);
pr_err("usb_ep_queue failed, err: %d", status);
}
@@ -822,27 +838,14 @@
struct f_mbim *mbim = req->context;
struct usb_cdc_notification *event = req->buf;
- int notif_c = 0;
-
- pr_info("dev:%p\n", mbim);
+ pr_debug("dev:%p\n", mbim);
spin_lock(&mbim->lock);
switch (req->status) {
case 0:
- pr_info("Notification %02x sent\n",
- event->bNotificationType);
-
- notif_c = atomic_dec_return(&mbim->not_port.notify_count);
-
- if (notif_c != 0) {
- pr_info("Continue to mbim_do_notify()");
- break;
- } else {
- pr_info("notify_count decreased to 0. Do not notify");
- spin_unlock(&mbim->lock);
- return;
- }
-
+ atomic_dec(&mbim->not_port.notify_count);
+ pr_debug("notify_count = %d",
+ atomic_read(&mbim->not_port.notify_count));
break;
case -ECONNRESET:
@@ -862,9 +865,7 @@
break;
}
- mbim->not_port.notify_req = req;
mbim_do_notify(mbim);
-
spin_unlock(&mbim->lock);
pr_info("dev:%p Exit\n", mbim);
@@ -1308,12 +1309,13 @@
pr_info("Set mbim port out_desc = 0x%p",
mbim->bam_port.out->desc);
+
+ pr_debug("Activate mbim\n");
+ mbim_bam_connect(mbim);
+
} else {
pr_info("PORTS already SET");
}
-
- pr_info("Activate mbim\n");
- mbim_bam_connect(mbim);
}
spin_lock(&mbim->lock);
@@ -1368,6 +1370,8 @@
mbim->not_port.notify->driver_data = NULL;
}
+ atomic_set(&mbim->not_port.notify_count, 0);
+
pr_info("mbim deactivated\n");
}
@@ -1789,7 +1793,6 @@
spin_lock(&_mbim_dev->lock);
_mbim_dev->is_open = true;
- mbim_notify(_mbim_dev);
spin_unlock(&_mbim_dev->lock);
pr_info("Exit, mbim file opened\n");
@@ -1805,7 +1808,6 @@
spin_lock(&mbim->lock);
mbim->is_open = false;
- mbim_notify(mbim);
spin_unlock(&mbim->lock);
mbim_unlock(&_mbim_dev->open_excl);
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index d895f27..e55fed7 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -166,7 +166,6 @@
phy = usb_get_transceiver();
if (phy && phy->otg) {
dev_dbg(&pdev->dev, "%s otg support available\n", __func__);
- hcd->driver->stop(hcd);
ret = otg_set_host(phy->otg, &hcd->self);
if (ret) {
dev_err(&pdev->dev, "%s otg_set_host failed\n",
@@ -211,6 +210,7 @@
usb_remove_hcd(hcd);
iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
kfree(xhci);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index a4c7131..92cbe6f 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -844,9 +844,14 @@
motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
dcp = motg->chg_type == USB_DCP_CHARGER;
- /* charging detection in progress due to cable plug-in */
- if (test_bit(B_SESS_VLD, &motg->inputs) && !device_bus_suspend &&
- !dcp) {
+ /*
+ * Abort suspend when,
+ * 1. charging detection in progress due to cable plug-in
+ * 2. host mode activation in progress due to Micro-A cable insertion
+ */
+
+ if ((test_bit(B_SESS_VLD, &motg->inputs) && !device_bus_suspend &&
+ !dcp) || test_bit(A_BUS_REQ, &motg->inputs)) {
enable_irq(motg->irq);
return -EBUSY;
}
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 712d41b..25da094 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -2838,15 +2838,7 @@
mfd->start_histogram = mdp_histogram_start;
mfd->stop_histogram = mdp_histogram_stop;
mdp4_display_intf_sel(if_no, DSI_CMD_INTF);
-
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- spin_lock_irqsave(&mdp_spin_lock, flag);
- mdp_intr_mask |= INTR_OVERLAY0_DONE;
- outp32(MDP_INTR_ENABLE, mdp_intr_mask);
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
#else
-
mfd->dma_fnc = mdp_dma2_update;
mfd->do_histogram = mdp_do_histogram;
mfd->start_histogram = mdp_histogram_start;
@@ -2873,7 +2865,7 @@
pdata->on = mdp4_dtv_on;
pdata->off = mdp4_dtv_off;
mfd->hw_refresh = TRUE;
- mfd->cursor_update = mdp_hw_cursor_update;
+ mfd->cursor_update = mdp_hw_cursor_sync_update;
mfd->dma_fnc = mdp4_dtv_overlay;
mfd->dma = &dma_e_data;
mfd->do_histogram = mdp_do_histogram;
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 7c87c44..1bd697e 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -1632,8 +1632,14 @@
data |= stage;
}
+ /*
+ * stage_commit may be called from overlay_unset
+ * for command panel, mdp clocks may be off at this time.
+ * so mdp clock enabled is necessary
+ */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
mdp_clk_ctrl(1);
+
mdp4_mixer_blend_setup(mixer);
off = 0;
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index c5442a7..10410a7 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -31,14 +31,14 @@
#include "mipi_dsi.h"
#include "mdp4.h"
-static int dsi_state;
-
-#define TOUT_PERIOD HZ /* 1 second */
-#define MS_100 (HZ/10) /* 100 ms */
-
static int vsync_start_y_adjust = 4;
#define MAX_CONTROLLER 1
+
+/*
+ * VSYNC_EXPIRE_TICK == 0 means clock always on
+ * VSYNC_EXPIRE_TICK == 4 is recommended
+ */
#define VSYNC_EXPIRE_TICK 4
static struct vsycn_ctrl {
@@ -51,10 +51,10 @@
u32 ov_done;
u32 dmap_koff;
u32 dmap_done;
+ u32 pan_display;
uint32 rdptr_intr_tot;
uint32 rdptr_sirq_tot;
atomic_t suspend;
- atomic_t vsync_resume;
int wait_vsync_cnt;
int blt_change;
int blt_free;
@@ -71,7 +71,6 @@
int vsync_enabled;
int clk_enabled;
int clk_control;
- int new_update;
ktime_t vsync_time;
struct work_struct clk_work;
} vsync_ctrl_db[MAX_CONTROLLER];
@@ -229,8 +228,10 @@
vctrl = &vsync_ctrl_db[cndx];
- if (atomic_read(&vctrl->suspend) > 0)
+ if (atomic_read(&vctrl->suspend)) {
+ pr_err("%s: suspended, no more pipe queue\n", __func__);
return;
+ }
mutex_lock(&vctrl->update_lock);
undx = vctrl->update_ndx;
@@ -363,12 +364,14 @@
mdp4_dsi_cmd_blt_ov_update(pipe);
pipe->ov_cnt++;
vctrl->ov_koff++;
+ INIT_COMPLETION(vctrl->ov_comp);
vsync_irq_enable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM);
} else {
+ INIT_COMPLETION(vctrl->dmap_comp);
vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
vctrl->dmap_koff++;
}
- pr_debug("%s: kickoff\n", __func__);
+ pr_debug("%s: kickoff, pid=%d\n", __func__, current->pid);
/* kickoff overlay engine */
mdp4_stat.kickoff_ov0++;
outpdw(MDP_BASE + 0x0004, 0);
@@ -392,15 +395,14 @@
{
struct vsycn_ctrl *vctrl;
unsigned long flags;
- int clk_set_on = 0;
int cndx = 0;
+ int clk_set_on = 0;
vctrl = &vsync_ctrl_db[cndx];
- pr_debug("%s: clk_enabled=%d vsycn_enabeld=%d req=%d\n", __func__,
- vctrl->clk_enabled, vctrl->vsync_enabled, enable);
-
mutex_lock(&vctrl->update_lock);
+ pr_debug("%s: clk_enabled=%d vsync_enabled=%d req=%d\n", __func__,
+ vctrl->clk_enabled, vctrl->vsync_enabled, enable);
if (vctrl->vsync_enabled == enable) {
mutex_unlock(&vctrl->update_lock);
@@ -410,6 +412,10 @@
vctrl->vsync_enabled = enable;
if (enable) {
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ vctrl->clk_control = 0;
+ vctrl->expire_tick = 0;
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
if (vctrl->clk_enabled == 0) {
pr_debug("%s: SET_CLK_ON\n", __func__);
mipi_dsi_clk_cfg(1);
@@ -417,26 +423,16 @@
vctrl->clk_enabled = 1;
clk_set_on = 1;
}
- spin_lock_irqsave(&vctrl->spin_lock, flags);
- vctrl->clk_control = 0;
- vctrl->expire_tick = 0;
- vctrl->new_update = 1;
if (clk_set_on) {
vsync_irq_enable(INTR_PRIMARY_RDPTR,
MDP_PRIM_RDPTR_TERM);
}
- spin_unlock_irqrestore(&vctrl->spin_lock, flags);
} else {
spin_lock_irqsave(&vctrl->spin_lock, flags);
- vctrl->clk_control = 1;
- if (vctrl->clk_enabled)
- vctrl->expire_tick = VSYNC_EXPIRE_TICK;
+ vctrl->expire_tick = VSYNC_EXPIRE_TICK;
spin_unlock_irqrestore(&vctrl->spin_lock, flags);
}
mutex_unlock(&vctrl->update_lock);
-
- if (vctrl->vsync_enabled && atomic_read(&vctrl->suspend) == 0)
- atomic_set(&vctrl->vsync_resume, 1);
}
void mdp4_dsi_cmd_wait4vsync(int cndx, long long *vtime)
@@ -514,7 +510,8 @@
struct vsycn_ctrl *vctrl;
vctrl = &vsync_ctrl_db[cndx];
- pr_debug("%s: ISR, cpu=%d\n", __func__, smp_processor_id());
+ pr_debug("%s: ISR, tick=%d pan=%d cpu=%d\n", __func__,
+ vctrl->expire_tick, vctrl->pan_display, smp_processor_id());
vctrl->rdptr_intr_tot++;
spin_lock(&vctrl->spin_lock);
@@ -525,8 +522,15 @@
if (vctrl->expire_tick) {
vctrl->expire_tick--;
- if (vctrl->expire_tick == 0)
- schedule_work(&vctrl->clk_work);
+ if (vctrl->expire_tick == 0) {
+ if (vctrl->pan_display <= 0) {
+ vctrl->clk_control = 1;
+ schedule_work(&vctrl->clk_work);
+ } else {
+ /* wait one more vsycn */
+ vctrl->expire_tick += 1;
+ }
+ }
}
spin_unlock(&vctrl->spin_lock);
}
@@ -546,11 +550,15 @@
spin_lock(&vctrl->spin_lock);
vsync_irq_disable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
vctrl->dmap_done++;
+
+ if (vctrl->pan_display)
+ vctrl->pan_display--;
+
diff = vctrl->ov_done - vctrl->dmap_done;
pr_debug("%s: ov_koff=%d ov_done=%d dmap_koff=%d dmap_done=%d cpu=%d\n",
__func__, vctrl->ov_koff, vctrl->ov_done, vctrl->dmap_koff,
vctrl->dmap_done, smp_processor_id());
- complete_all(&vctrl->dmap_comp);
+ complete(&vctrl->dmap_comp);
if (diff <= 0) {
if (vctrl->blt_wait)
vctrl->blt_wait = 0;
@@ -586,7 +594,7 @@
spin_lock(&vctrl->spin_lock);
vsync_irq_disable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM);
vctrl->ov_done++;
- complete_all(&vctrl->ov_comp);
+ complete(&vctrl->ov_comp);
diff = vctrl->ov_done - vctrl->dmap_done;
pr_debug("%s: ov_koff=%d ov_done=%d dmap_koff=%d dmap_done=%d cpu=%d\n",
@@ -622,20 +630,24 @@
static void clk_ctrl_work(struct work_struct *work)
{
+ unsigned long flags;
struct vsycn_ctrl *vctrl =
container_of(work, typeof(*vctrl), clk_work);
- unsigned long flags;
mutex_lock(&vctrl->update_lock);
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
if (vctrl->clk_control && vctrl->clk_enabled) {
- pr_debug("%s: SET_CLK_OFF\n", __func__);
- mdp_clk_ctrl(0);
- mipi_dsi_clk_cfg(0);
- spin_lock_irqsave(&vctrl->spin_lock, flags);
vsync_irq_disable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM);
vctrl->clk_enabled = 0;
vctrl->clk_control = 0;
spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+ /* make sure dsi link is idle */
+ mipi_dsi_mdp_busy_wait();
+ mipi_dsi_clk_cfg(0);
+ mdp_clk_ctrl(0);
+ pr_debug("%s: SET_CLK_OFF, pid=%d\n", __func__, current->pid);
+ } else {
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
}
mutex_unlock(&vctrl->update_lock);
}
@@ -652,8 +664,7 @@
cndx = 0;
vctrl = &vsync_ctrl_db[0];
- if (atomic_read(&vctrl->suspend) > 0 ||
- atomic_read(&vctrl->vsync_resume) == 0)
+ if (atomic_read(&vctrl->suspend) > 0)
return 0;
spin_lock_irqsave(&vctrl->spin_lock, flags);
@@ -671,6 +682,8 @@
spin_unlock_irqrestore(&vctrl->spin_lock, flags);
ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", vsync_tick);
+ pr_debug("%s: UEVENT\n", __func__);
+
buf[strlen(buf) + 1] = '\0';
return ret;
}
@@ -695,7 +708,6 @@
init_completion(&vctrl->dmap_comp);
init_completion(&vctrl->vsync_comp);
spin_lock_init(&vctrl->spin_lock);
- atomic_set(&vctrl->vsync_resume, 1);
INIT_WORK(&vctrl->clk_work, clk_ctrl_work);
}
@@ -704,20 +716,6 @@
primary_rdptr_isr(0);
}
-void mdp4_overlay_dsi_state_set(int state)
-{
- unsigned long flag;
-
- spin_lock_irqsave(&mdp_spin_lock, flag);
- dsi_state = state;
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
-}
-
-int mdp4_overlay_dsi_state_get(void)
-{
- return dsi_state;
-}
-
static __u32 msm_fb_line_length(__u32 fb_index, __u32 xres, int bpp)
{
/*
@@ -942,6 +940,7 @@
pipe->srcp0_addr = (uint32)src;
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ mdp_clk_ctrl(1);
mdp4_overlay_rgb_setup(pipe);
@@ -957,6 +956,7 @@
mdp4_mixer_stage_commit(pipe->mixer_num);
/* MDP cmd block disable */
+ mdp_clk_ctrl(0);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
@@ -991,9 +991,10 @@
struct msm_fb_data_type *mfd;
struct vsycn_ctrl *vctrl;
- pr_debug("%s+:\n", __func__);
+ pr_debug("%s+: pid=%d\n", __func__, current->pid);
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+ mfd->cont_splash_done = 1;
vctrl = &vsync_ctrl_db[cndx];
vctrl->mfd = mfd;
@@ -1006,7 +1007,6 @@
mdp4_iommu_attach();
atomic_set(&vctrl->suspend, 0);
- pr_debug("%s-:\n", __func__);
if (!vctrl->sysfs_created) {
ret = sysfs_create_group(&vctrl->dev->kobj,
@@ -1022,6 +1022,8 @@
vctrl->sysfs_created = 1;
}
+ pr_debug("%s-:\n", __func__);
+
return ret;
}
@@ -1034,8 +1036,9 @@
struct mdp4_overlay_pipe *pipe;
struct vsync_update *vp;
int undx;
+ int need_wait, cnt;
- pr_debug("%s+:\n", __func__);
+ pr_debug("%s+: pid=%d\n", __func__, current->pid);
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
@@ -1046,26 +1049,40 @@
return ret;
}
+ need_wait = 0;
+ mutex_lock(&vctrl->update_lock);
atomic_set(&vctrl->suspend, 1);
- atomic_set(&vctrl->vsync_resume, 0);
complete_all(&vctrl->vsync_comp);
+ pr_debug("%s: clk=%d pan=%d\n", __func__,
+ vctrl->clk_enabled, vctrl->pan_display);
+ if (vctrl->clk_enabled)
+ need_wait = 1;
+ mutex_unlock(&vctrl->update_lock);
+
+ cnt = 0;
+ if (need_wait) {
+ while (vctrl->clk_enabled) {
+ msleep(20);
+ cnt++;
+ if (cnt > 10)
+ break;
+ }
+ }
+
+ /* message for system suspnded */
+ if (cnt > 10)
+ pr_err("%s:Error, mdp clocks NOT off\n", __func__);
+ else
+ pr_debug("%s: mdp clocks off at cnt=%d\n", __func__, cnt);
+
/* sanity check, free pipes besides base layer */
mdp4_overlay_unset_mixer(pipe->mixer_num);
mdp4_mixer_stage_down(pipe, 1);
mdp4_overlay_pipe_free(pipe);
vctrl->base_pipe = NULL;
- if (vctrl->clk_enabled) {
- /*
- * in case of suspend, vsycn_ctrl off is not
- * received from frame work which left clock on
- * then, clock need to be turned off here
- */
- mdp_clk_ctrl(0);
- }
-
undx = vctrl->update_ndx;
vp = &vctrl->vlist[undx];
if (vp->update_cnt) {
@@ -1076,23 +1093,7 @@
vp->update_cnt = 0; /* empty queue */
}
- vctrl->clk_enabled = 0;
- vctrl->vsync_enabled = 0;
- vctrl->clk_control = 0;
- vctrl->expire_tick = 0;
-
- vsync_irq_disable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM);
-
-
pr_debug("%s-:\n", __func__);
-
- /*
- * footswitch off
- * this will casue all mdp register
- * to be reset to default
- * after footswitch on later
- */
-
return ret;
}
@@ -1127,7 +1128,7 @@
struct vsycn_ctrl *vctrl;
struct mdp4_overlay_pipe *pipe;
unsigned long flags;
- long long tick;
+ int clk_set_on = 0;
mutex_lock(&mfd->dma->ov_mutex);
vctrl = &vsync_ctrl_db[cndx];
@@ -1145,25 +1146,32 @@
}
mutex_lock(&vctrl->update_lock);
- if (!vctrl->clk_enabled) {
- pr_err("%s: mdp clocks disabled\n", __func__);
+ if (atomic_read(&vctrl->suspend)) {
mutex_unlock(&vctrl->update_lock);
mutex_unlock(&mfd->dma->ov_mutex);
+ pr_err("%s: suspended, no more pan display\n", __func__);
return;
-
}
- mutex_unlock(&vctrl->update_lock);
spin_lock_irqsave(&vctrl->spin_lock, flags);
- if (vctrl->expire_tick) {
- /*
- * in the middle of shutting clocks down
- * delay to allow pan display to go through
- */
+ vctrl->clk_control = 0;
+ vctrl->pan_display++;
+ if (!vctrl->clk_enabled) {
+ clk_set_on = 1;
+ vctrl->clk_enabled = 1;
vctrl->expire_tick = VSYNC_EXPIRE_TICK;
}
spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+ if (clk_set_on) {
+ pr_debug("%s: SET_CLK_ON\n", __func__);
+ mipi_dsi_clk_cfg(1);
+ mdp_clk_ctrl(1);
+ vsync_irq_enable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM);
+ }
+
+ mutex_unlock(&vctrl->update_lock);
+
if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE) {
mdp4_mipi_vsync_enable(mfd, pipe, 0);
mdp4_overlay_setup_pipe_addr(mfd, pipe);
@@ -1172,8 +1180,6 @@
mdp4_overlay_mdp_perf_upd(mfd, 1);
mdp4_dsi_cmd_pipe_commit(cndx, 0);
- mdp4_dsi_cmd_wait4vsync(cndx, &tick);
mdp4_overlay_mdp_perf_upd(mfd, 0);
mutex_unlock(&mfd->dma->ov_mutex);
-
}
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index a83c340..5551c9d 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -1073,7 +1073,7 @@
uint8 *buf;
unsigned int buf_offset;
int bpp;
- int cndx = 0;
+ int cnt, cndx = 0;
struct vsycn_ctrl *vctrl;
struct mdp4_overlay_pipe *pipe;
@@ -1104,12 +1104,14 @@
mdp_update_pm(mfd, vsync_ctrl_db[0].vsync_time);
mdp4_overlay_mdp_perf_upd(mfd, 1);
- mdp4_dsi_video_pipe_commit(cndx, 0);
- if (pipe->ov_blt_addr)
- mdp4_dsi_video_wait4ov(cndx);
- else
- mdp4_dsi_video_wait4dmap(cndx);
+ cnt = mdp4_dsi_video_pipe_commit(cndx, 0);
+ if (cnt) {
+ if (pipe->ov_blt_addr)
+ mdp4_dsi_video_wait4ov(cndx);
+ else
+ mdp4_dsi_video_wait4dmap(cndx);
+ }
mdp4_overlay_mdp_perf_upd(mfd, 0);
mutex_unlock(&mfd->dma->ov_mutex);
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index 67690cf..e71f49f 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -1114,6 +1114,7 @@
int cndx = 0;
struct vsycn_ctrl *vctrl;
struct mdp4_overlay_pipe *pipe;
+ int wait = 0;
mutex_lock(&mfd->dma->ov_mutex);
if (!mfd->panel_power_on) {
@@ -1145,8 +1146,12 @@
mdp4_dtv_pipe_queue(0, pipe);
}
mdp_update_pm(mfd, vsync_ctrl_db[0].vsync_time);
+
+ if (hdmi_prim_display)
+ wait = 1;
+
mdp4_overlay_mdp_perf_upd(mfd, 1);
- mdp4_dtv_pipe_commit(cndx, 0);
+ mdp4_dtv_pipe_commit(cndx, wait);
mdp4_overlay_mdp_perf_upd(mfd, 0);
mutex_unlock(&mfd->dma->ov_mutex);
}
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index 9e0c411..df5c262 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -961,7 +961,7 @@
uint8 *buf;
unsigned int buf_offset;
int bpp;
- int cndx = 0;
+ int cnt, cndx = 0;
struct vsycn_ctrl *vctrl;
struct mdp4_overlay_pipe *pipe;
@@ -993,13 +993,13 @@
mdp4_overlay_mdp_perf_upd(mfd, 1);
-
- mdp4_lcdc_pipe_commit(cndx, 0);
-
- if (pipe->ov_blt_addr)
- mdp4_lcdc_wait4ov(cndx);
- else
- mdp4_lcdc_wait4dmap(cndx);
+ cnt = mdp4_lcdc_pipe_commit(cndx, 0);
+ if (cnt) {
+ if (pipe->ov_blt_addr)
+ mdp4_lcdc_wait4ov(cndx);
+ else
+ mdp4_lcdc_wait4dmap(cndx);
+ }
mdp4_overlay_mdp_perf_upd(mfd, 0);
mutex_unlock(&mfd->dma->ov_mutex);
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index 516722e..ee9ca3c 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -630,6 +630,7 @@
if (panel & MDP4_PANEL_ATV)
mdp4_overlay1_done_atv();
#endif
+ mdp_hw_cursor_done();
}
#if defined(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL)
if (isr & INTR_OVERLAY2_DONE) {
diff --git a/drivers/video/msm/mdp_cursor.c b/drivers/video/msm/mdp_cursor.c
index f8c08e3..b5930a1 100644
--- a/drivers/video/msm/mdp_cursor.c
+++ b/drivers/video/msm/mdp_cursor.c
@@ -52,7 +52,11 @@
/* disable vsync */
spin_lock_irqsave(&mdp_spin_lock, flag);
- mdp_disable_irq(MDP_OVERLAY0_TERM);
+ if (hdmi_prim_display)
+ mdp_disable_irq(MDP_OVERLAY1_TERM);
+ else
+ mdp_disable_irq(MDP_OVERLAY0_TERM);
+
spin_unlock_irqrestore(&mdp_spin_lock, flag);
}
@@ -78,29 +82,37 @@
*
* Moving this code out of the ISR will cause the MDP to underrun!
*/
+ uint32_t base = 0;
+
+ if (hdmi_prim_display)
+ base = ((uint32_t)(MDP_BASE + 0xB0000));
+ else
+ base = ((uint32_t)(MDP_BASE + 0x90000));
+
+
spin_lock(&mdp_spin_lock);
if (sync_disabled) {
spin_unlock(&mdp_spin_lock);
return;
}
- MDP_OUTP(MDP_BASE + 0x90044, (height << 16) | width);
- MDP_OUTP(MDP_BASE + 0x90048, cursor_buf_phys);
+ MDP_OUTP(base + 0x44, (height << 16) | width);
+ MDP_OUTP(base + 0x48, cursor_buf_phys);
- MDP_OUTP(MDP_BASE + 0x90060,
+ MDP_OUTP(base + 0x60,
(transp_en << 3) | (calpha_en << 1) |
- (inp32(MDP_BASE + 0x90060) & 0x1));
+ (inp32(base + 0x60) & 0x1));
- MDP_OUTP(MDP_BASE + 0x90064, (alpha << 24));
- MDP_OUTP(MDP_BASE + 0x90068, (0xffffff & bg_color));
- MDP_OUTP(MDP_BASE + 0x9006C, (0xffffff & bg_color));
+ MDP_OUTP(base + 0x64, (alpha << 24));
+ MDP_OUTP(base + 0x68, (0xffffff & bg_color));
+ MDP_OUTP(base + 0x6C, (0xffffff & bg_color));
/* enable/disable the cursor as per the last request */
- if (cursor_enabled && !(inp32(MDP_BASE + 0x90060) & (0x1)))
- MDP_OUTP(MDP_BASE + 0x90060, inp32(MDP_BASE + 0x90060) | 0x1);
- else if (!cursor_enabled && (inp32(MDP_BASE + 0x90060) & (0x1)))
- MDP_OUTP(MDP_BASE + 0x90060,
- inp32(MDP_BASE + 0x90060) & (~0x1));
+ if (cursor_enabled && !(inp32(base + 0x60) & (0x1)))
+ MDP_OUTP(base + 0x60, inp32(base + 0x60) | 0x1);
+ else if (!cursor_enabled && (inp32(base + 0x60) & (0x1)))
+ MDP_OUTP(base + 0x60,
+ inp32(base + 0x60) & (~0x1));
/* enqueue the task to disable MDP interrupts */
queue_work(mdp_cursor_ctrl_wq, &mdp_cursor_ctrl_worker);
@@ -119,17 +131,26 @@
if (sync_disabled) {
/* cancel pending task to disable MDP interrupts */
- if (work_pending(&mdp_cursor_ctrl_worker))
+ if (work_pending(&mdp_cursor_ctrl_worker)) {
cancel_work_sync(&mdp_cursor_ctrl_worker);
- else
+ } else {
/* enable irq */
- mdp_enable_irq(MDP_OVERLAY0_TERM);
+ if (hdmi_prim_display)
+ mdp_enable_irq(MDP_OVERLAY1_TERM);
+ else
+ mdp_enable_irq(MDP_OVERLAY0_TERM);
+ }
sync_disabled = 0;
/* enable vsync intr */
- outp32(MDP_INTR_CLEAR, INTR_OVERLAY0_DONE);
- mdp_intr_mask |= INTR_OVERLAY0_DONE;
+ if (hdmi_prim_display) {
+ outp32(MDP_INTR_CLEAR, INTR_OVERLAY1_DONE);
+ mdp_intr_mask |= INTR_OVERLAY1_DONE;
+ } else {
+ outp32(MDP_INTR_CLEAR, INTR_OVERLAY0_DONE);
+ mdp_intr_mask |= INTR_OVERLAY0_DONE;
+ }
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
}
}
@@ -140,14 +161,20 @@
struct fb_image *img = &cursor->image;
unsigned long flag;
int sync_needed = 0, ret = 0;
+ uint32_t base = 0;
if ((img->width > MDP_CURSOR_WIDTH) ||
(img->height > MDP_CURSOR_HEIGHT) ||
(img->depth != 32))
return -EINVAL;
+ if (hdmi_prim_display)
+ base = ((uint32_t)(MDP_BASE + 0xB0000));
+ else
+ base = ((uint32_t)(MDP_BASE + 0x90000));
+
if (cursor->set & FB_CUR_SETPOS)
- MDP_OUTP(MDP_BASE + 0x9004c, (img->dy << 16) | img->dx);
+ MDP_OUTP(base + 0x4c, (img->dy << 16) | img->dx);
if (cursor->set & FB_CUR_SETIMAGE) {
ret = copy_from_user(mfd->cursor_buf, img->data,
diff --git a/drivers/video/msm/mdss/mdss_edp.c b/drivers/video/msm/mdss/mdss_edp.c
index 9460d71..b35be75 100644
--- a/drivers/video/msm/mdss/mdss_edp.c
+++ b/drivers/video/msm/mdss/mdss_edp.c
@@ -22,6 +22,8 @@
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pwm.h>
#include <asm/system.h>
#include <asm/mach-types.h>
@@ -37,15 +39,14 @@
#define VDDA_UA_ON_LOAD 100000 /* uA units */
#define VDDA_UA_OFF_LOAD 100 /* uA units */
-
static int mdss_edp_get_base_address(struct mdss_edp_drv_pdata *edp_drv);
static int mdss_edp_get_mmss_cc_base_address(struct mdss_edp_drv_pdata
*edp_drv);
static int mdss_edp_regulator_init(struct mdss_edp_drv_pdata *edp_drv);
static int mdss_edp_regulator_on(struct mdss_edp_drv_pdata *edp_drv);
static int mdss_edp_regulator_off(struct mdss_edp_drv_pdata *edp_drv);
-
static int mdss_edp_gpio_panel_en(struct mdss_edp_drv_pdata *edp_drv);
+static int mdss_edp_pwm_config(struct mdss_edp_drv_pdata *edp_drv);
static void mdss_edp_edid2pinfo(struct mdss_edp_drv_pdata *edp_drv);
static void mdss_edp_fill_edid_data(struct mdss_edp_drv_pdata *edp_drv);
@@ -134,7 +135,7 @@
}
/*
- * Enables the gpio that supply power to the panel
+ * Enables the gpio that supply power to the panel and enable the backlight
*/
static int mdss_edp_gpio_panel_en(struct mdss_edp_drv_pdata *edp_drv)
{
@@ -143,7 +144,8 @@
edp_drv->gpio_panel_en = of_get_named_gpio(edp_drv->pdev->dev.of_node,
"gpio-panel-en", 0);
if (!gpio_is_valid(edp_drv->gpio_panel_en)) {
- pr_err("%s: gpio_panel_en not specified\n", __func__);
+ pr_err("%s: gpio_panel_en=%d not specified\n", __func__,
+ edp_drv->gpio_panel_en);
goto gpio_err;
}
@@ -171,7 +173,94 @@
return -ENODEV;
}
-static void mdss_edp_config_sync(unsigned char *edp_base)
+static int mdss_edp_pwm_config(struct mdss_edp_drv_pdata *edp_drv)
+{
+ int ret = 0;
+
+ ret = of_property_read_u32(edp_drv->pdev->dev.of_node,
+ "qcom,panel-pwm-period", &edp_drv->pwm_period);
+ if (ret) {
+ pr_err("%s: panel pwm period is not specified, %d", __func__,
+ edp_drv->pwm_period);
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(edp_drv->pdev->dev.of_node,
+ "qcom,panel-lpg-channel", &edp_drv->lpg_channel);
+ if (ret) {
+ pr_err("%s: panel lpg channel is not specified, %d", __func__,
+ edp_drv->lpg_channel);
+ return -EINVAL;
+ }
+
+ edp_drv->bl_pwm = pwm_request(edp_drv->lpg_channel, "lcd-backlight");
+ if (edp_drv->bl_pwm == NULL || IS_ERR(edp_drv->bl_pwm)) {
+ pr_err("%s: pwm request failed", __func__);
+ edp_drv->bl_pwm = NULL;
+ return -EIO;
+ }
+
+ edp_drv->gpio_panel_pwm = of_get_named_gpio(edp_drv->pdev->dev.of_node,
+ "gpio-panel-pwm", 0);
+ if (!gpio_is_valid(edp_drv->gpio_panel_pwm)) {
+ pr_err("%s: gpio_panel_pwm=%d not specified\n", __func__,
+ edp_drv->gpio_panel_pwm);
+ goto edp_free_pwm;
+ }
+
+ ret = gpio_request(edp_drv->gpio_panel_pwm, "disp_pwm");
+ if (ret) {
+ pr_err("%s: Request reset gpio_panel_pwm failed, ret=%d\n",
+ __func__, ret);
+ goto edp_free_gpio_pwm;
+ }
+
+ return 0;
+
+edp_free_gpio_pwm:
+ gpio_free(edp_drv->gpio_panel_pwm);
+edp_free_pwm:
+ pwm_free(edp_drv->bl_pwm);
+ return -ENODEV;
+}
+
+void mdss_edp_set_backlight(struct mdss_panel_data *pdata, u32 bl_level)
+{
+ int ret = 0;
+ struct mdss_edp_drv_pdata *edp_drv = NULL;
+ int bl_max;
+
+ edp_drv = container_of(pdata, struct mdss_edp_drv_pdata, panel_data);
+ if (!edp_drv) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return;
+ }
+
+ bl_max = edp_drv->panel_data.panel_info.bl_max;
+ if (bl_level > bl_max)
+ bl_level = bl_max;
+
+ if (edp_drv->bl_pwm == NULL) {
+ pr_err("%s: edp_drv->bl_pwm=NULL.\n", __func__);
+ return;
+ }
+
+ ret = pwm_config(edp_drv->bl_pwm,
+ bl_level * edp_drv->pwm_period / bl_max,
+ edp_drv->pwm_period);
+ if (ret) {
+ pr_err("%s: pwm_config() failed err=%d.\n", __func__, ret);
+ return;
+ }
+
+ ret = pwm_enable(edp_drv->bl_pwm);
+ if (ret) {
+ pr_err("%s: pwm_enable() failed err=%d\n", __func__, ret);
+ return;
+ }
+}
+
+void mdss_edp_config_sync(unsigned char *edp_base)
{
int ret = 0;
@@ -251,6 +340,7 @@
return -EINVAL;
}
+ pwm_disable(edp_drv->bl_pwm);
mdss_edp_enable(edp_drv->edp_base, 0);
mdss_edp_unconfig_clk(edp_drv->edp_base, edp_drv->mmss_cc_base);
mdss_edp_enable_mainlink(edp_drv->edp_base, 0);
@@ -322,9 +412,12 @@
int ret;
mdss_edp_edid2pinfo(edp_drv);
+ edp_drv->panel_data.panel_info.bl_min = 1;
+ edp_drv->panel_data.panel_info.bl_max = 255;
edp_drv->panel_data.on = mdss_edp_on;
edp_drv->panel_data.off = mdss_edp_off;
+ edp_drv->panel_data.set_backlight = mdss_edp_set_backlight;
ret = mdss_register_panel(&edp_drv->panel_data);
if (ret) {
@@ -468,12 +561,19 @@
if (ret)
goto edp_clk_deinit;
+ ret = mdss_edp_pwm_config(edp_drv);
+ if (ret)
+ goto edp_free_gpio_panel_en;
+
mdss_edp_fill_edid_data(edp_drv);
mdss_edp_fill_dpcd_data(edp_drv);
mdss_edp_device_register(edp_drv);
return 0;
+
+edp_free_gpio_panel_en:
+ gpio_free(edp_drv->gpio_panel_en);
edp_clk_deinit:
mdss_edp_clk_deinit(edp_drv);
mdss_edp_regulator_off(edp_drv);
diff --git a/drivers/video/msm/mdss/mdss_edp.h b/drivers/video/msm/mdss/mdss_edp.h
index 72c061f..00ef206 100644
--- a/drivers/video/msm/mdss/mdss_edp.h
+++ b/drivers/video/msm/mdss/mdss_edp.h
@@ -92,6 +92,12 @@
/* gpios */
int gpio_panel_en;
+ int gpio_panel_pwm;
+
+ /* backlight */
+ struct pwm_device *bl_pwm;
+ int lpg_channel;
+ int pwm_period;
};
void mdss_edp_phy_sw_reset(unsigned char *edp_base);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 7f41221..c2d5f28 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -1173,7 +1173,7 @@
if (rc) {
DEV_ERR("%s: core hdmi_msm_enable_power failed rc = %d\n",
__func__, rc);
- goto disable_hpd_power;
+ return rc;
}
rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CEC_PM, 1);
if (rc) {
@@ -1185,8 +1185,6 @@
return rc;
disable_core_power:
hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CORE_PM, 0);
-disable_hpd_power:
- hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, 0);
return rc;
} /* hdmi_tx_core_on */
diff --git a/drivers/video/msm/mipi_dsi.c b/drivers/video/msm/mipi_dsi.c
index 7d534ed..a58010e 100644
--- a/drivers/video/msm/mipi_dsi.c
+++ b/drivers/video/msm/mipi_dsi.c
@@ -69,6 +69,8 @@
struct msm_fb_data_type *mfd;
struct msm_panel_info *pinfo;
+ pr_debug("%s+:\n", __func__);
+
mfd = platform_get_drvdata(pdev);
pinfo = &mfd->panel_info;
@@ -77,15 +79,14 @@
else
down(&mfd->dma->mutex);
- mdp4_overlay_dsi_state_set(ST_DSI_SUSPEND);
+ if (mfd->panel_info.type == MIPI_CMD_PANEL) {
+ mipi_dsi_prepare_clocks();
+ mipi_dsi_ahb_ctrl(1);
+ mipi_dsi_clk_enable();
- /* make sure dsi clk is on so that
- * dcs commands can be sent
- */
- mipi_dsi_clk_cfg(1);
-
- /* make sure dsi_cmd_mdp is idle */
- mipi_dsi_cmd_mdp_busy();
+ /* make sure dsi_cmd_mdp is idle */
+ mipi_dsi_cmd_mdp_busy();
+ }
/*
* Desctiption: change to DSI_CMD_MODE since it needed to
@@ -146,6 +147,8 @@
u32 dummy_xres, dummy_yres;
int target_type = 0;
+ pr_debug("%s+:\n", __func__);
+
mfd = platform_get_drvdata(pdev);
fbi = mfd->fbi;
var = &fbi->var;
@@ -305,14 +308,15 @@
}
mipi_dsi_set_tear_on(mfd);
}
+ mipi_dsi_clk_disable();
+ mipi_dsi_ahb_ctrl(0);
+ mipi_dsi_unprepare_clocks();
}
#ifdef CONFIG_MSM_BUS_SCALING
mdp_bus_scale_update_request(2);
#endif
- mdp4_overlay_dsi_state_set(ST_DSI_RESUME);
-
if (mdp_rev >= MDP_REV_41)
mutex_unlock(&mfd->dma->ov_mutex);
else
diff --git a/drivers/video/msm/mipi_dsi.h b/drivers/video/msm/mipi_dsi.h
index 0f37f6f..2711c1a 100644
--- a/drivers/video/msm/mipi_dsi.h
+++ b/drivers/video/msm/mipi_dsi.h
@@ -319,7 +319,7 @@
void mipi_dsi_post_kickoff_del(struct dsi_kickoff_action *act);
void mipi_dsi_controller_cfg(int enable);
void mipi_dsi_sw_reset(void);
-void mipi_dsi_mdp_busy_wait(struct msm_fb_data_type *mfd);
+void mipi_dsi_mdp_busy_wait(void);
irqreturn_t mipi_dsi_isr(int irq, void *ptr);
diff --git a/drivers/video/msm/mipi_dsi_host.c b/drivers/video/msm/mipi_dsi_host.c
index 60311dc..bea6b4e 100644
--- a/drivers/video/msm/mipi_dsi_host.c
+++ b/drivers/video/msm/mipi_dsi_host.c
@@ -50,6 +50,7 @@
static int dsi_ctrl_lock;
static int dsi_mdp_busy;
static struct mutex cmd_mutex;
+static struct mutex clk_mutex;
static struct list_head pre_kickoff_list;
static struct list_head post_kickoff_list;
@@ -99,6 +100,7 @@
spin_lock_init(&dsi_mdp_lock);
spin_lock_init(&dsi_clk_lock);
mutex_init(&cmd_mutex);
+ mutex_init(&clk_mutex);
INIT_LIST_HEAD(&pre_kickoff_list);
INIT_LIST_HEAD(&post_kickoff_list);
@@ -165,12 +167,12 @@
void mipi_dsi_clk_cfg(int on)
{
- unsigned long flags;
static int dsi_clk_cnt;
- spin_lock_irqsave(&mdp_spin_lock, flags);
+ mutex_lock(&clk_mutex);
if (on) {
if (dsi_clk_cnt == 0) {
+ mipi_dsi_prepare_clocks();
mipi_dsi_ahb_ctrl(1);
mipi_dsi_clk_enable();
}
@@ -181,10 +183,13 @@
if (dsi_clk_cnt == 0) {
mipi_dsi_clk_disable();
mipi_dsi_ahb_ctrl(0);
+ mipi_dsi_unprepare_clocks();
}
}
}
- spin_unlock_irqrestore(&mdp_spin_lock, flags);
+ pr_debug("%s: on=%d clk_cnt=%d pid=%d\n", __func__,
+ on, dsi_clk_cnt, current->pid);
+ mutex_unlock(&clk_mutex);
}
void mipi_dsi_turn_on_clks(void)
@@ -1022,31 +1027,13 @@
wmb();
}
-void mipi_dsi_mdp_busy_wait(struct msm_fb_data_type *mfd)
+void mipi_dsi_mdp_busy_wait(void)
{
- unsigned long flag;
- int need_wait = 0;
-
- pr_debug("%s: start pid=%d\n",
- __func__, current->pid);
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- if (dsi_mdp_busy == TRUE) {
- INIT_COMPLETION(dsi_mdp_comp);
- need_wait++;
- }
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
- if (need_wait) {
- /* wait until DMA finishes the current job */
- pr_debug("%s: pending pid=%d\n",
- __func__, current->pid);
- wait_for_completion(&dsi_mdp_comp);
- }
- pr_debug("%s: done pid=%d\n",
- __func__, current->pid);
+ mutex_lock(&cmd_mutex);
+ mipi_dsi_cmd_mdp_busy();
+ mutex_unlock(&cmd_mutex);
}
-
void mipi_dsi_cmd_mdp_start(void)
{
unsigned long flag;
@@ -1054,8 +1041,9 @@
mipi_dsi_mdp_stat_inc(STAT_DSI_START);
spin_lock_irqsave(&dsi_mdp_lock, flag);
- mipi_dsi_enable_irq(DSI_MDP_TERM);
- dsi_mdp_busy = TRUE;
+ mipi_dsi_enable_irq(DSI_MDP_TERM);
+ dsi_mdp_busy = TRUE;
+ INIT_COMPLETION(dsi_mdp_comp);
spin_unlock_irqrestore(&dsi_mdp_lock, flag);
}
@@ -1089,14 +1077,28 @@
void mipi_dsi_set_tear_on(struct msm_fb_data_type *mfd)
{
- mipi_dsi_buf_init(&dsi_tx_buf);
- mipi_dsi_cmds_tx(&dsi_tx_buf, &dsi_tear_on_cmd, 1);
+ struct dcs_cmd_req cmdreq;
+
+ cmdreq.cmds = &dsi_tear_on_cmd;
+ cmdreq.cmds_cnt = 1;
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+
+ mipi_dsi_cmdlist_put(&cmdreq);
}
void mipi_dsi_set_tear_off(struct msm_fb_data_type *mfd)
{
- mipi_dsi_buf_init(&dsi_tx_buf);
- mipi_dsi_cmds_tx(&dsi_tx_buf, &dsi_tear_off_cmd, 1);
+ struct dcs_cmd_req cmdreq;
+
+ cmdreq.cmds = &dsi_tear_off_cmd;
+ cmdreq.cmds_cnt = 1;
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+
+ mipi_dsi_cmdlist_put(&cmdreq);
}
int mipi_dsi_cmd_reg_tx(uint32 data)
@@ -1137,7 +1139,6 @@
struct dsi_cmd_desc *cm;
uint32 dsi_ctrl, ctrl;
int i, video_mode;
- unsigned long flag;
/* turn on cmd mode
* for video mode, do not send cmds more than
@@ -1151,10 +1152,6 @@
MIPI_OUTP(MIPI_DSI_BASE + 0x0000, ctrl);
}
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- dsi_mdp_busy = TRUE;
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
cm = cmds;
mipi_dsi_buf_init(tp);
for (i = 0; i < cnt; i++) {
@@ -1170,11 +1167,6 @@
if (video_mode)
MIPI_OUTP(MIPI_DSI_BASE + 0x0000, dsi_ctrl); /* restore */
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- dsi_mdp_busy = FALSE;
- complete(&dsi_mdp_comp);
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
return cnt;
}
@@ -1204,7 +1196,6 @@
{
int cnt, len, diff, pkt_size;
char cmd;
- unsigned long flag;
if (mfd->panel_info.mipi.no_max_pkt_size) {
/* Only support rlen = 4*n */
@@ -1241,10 +1232,6 @@
#endif
}
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- dsi_mdp_busy = TRUE;
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
if (!mfd->panel_info.mipi.no_max_pkt_size) {
/* packet size need to be set at every read */
pkt_size = len;
@@ -1279,11 +1266,6 @@
mipi_dsi_cmd_dma_rx(rp, cnt);
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- dsi_mdp_busy = FALSE;
- complete(&dsi_mdp_comp);
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
if (mfd->panel_info.mipi.no_max_pkt_size) {
/*
* remove extra 2 bytes from previous
@@ -1327,7 +1309,6 @@
struct dsi_cmd_desc *cmds;
int cnt, len, diff, pkt_size;
char cmd;
- unsigned long flag;
if (req->flags & CMD_REQ_NO_MAX_PKT_SIZE) {
/* Only support rlen = 4*n */
@@ -1359,10 +1340,6 @@
cnt = len + 6; /* 4 bytes header + 2 bytes crc */
}
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- dsi_mdp_busy = TRUE;
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
if (!(req->flags & CMD_REQ_NO_MAX_PKT_SIZE)) {
@@ -1399,11 +1376,6 @@
mipi_dsi_cmd_dma_rx(rp, cnt);
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- dsi_mdp_busy = FALSE;
- complete(&dsi_mdp_comp);
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
if (req->flags & CMD_REQ_NO_MAX_PKT_SIZE) {
/*
* remove extra 2 bytes from previous
@@ -1515,24 +1487,43 @@
return rlen;
}
-void mipi_dsi_cmd_mdp_busy(void)
+static void mipi_dsi_wait_for_video_eng_busy(void)
{
u32 status;
+ int sleep_us = 4000;
+
+ /*
+ * if video mode engine was not busy (in BLLP)
+ * wait to pass BLLP
+ */
+
+ /* check for VIDEO_MODE_ENGINE_BUSY */
+ readl_poll((MIPI_DSI_BASE + 0x0004), /* DSI_STATUS */
+ status,
+ (status & 0x08),
+ sleep_us);
+}
+
+void mipi_dsi_cmd_mdp_busy(void)
+{
unsigned long flags;
int need_wait = 0;
+ pr_debug("%s: start pid=%d\n",
+ __func__, current->pid);
spin_lock_irqsave(&dsi_mdp_lock, flags);
- status = MIPI_INP(MIPI_DSI_BASE + 0x0004);/* DSI_STATUS */
- if (status & 0x04) { /* MDP BUSY */
- INIT_COMPLETION(dsi_mdp_comp);
- need_wait = 1;
- pr_debug("%s: status=%x need_wait\n", __func__, (int)status);
- mipi_dsi_enable_irq(DSI_MDP_TERM);
- }
+ if (dsi_mdp_busy == TRUE)
+ need_wait++;
spin_unlock_irqrestore(&dsi_mdp_lock, flags);
- if (need_wait)
+ if (need_wait) {
+ /* wait until DMA finishes the current job */
+ pr_debug("%s: pending pid=%d\n",
+ __func__, current->pid);
wait_for_completion(&dsi_mdp_comp);
+ }
+ pr_debug("%s: done pid=%d\n",
+ __func__, current->pid);
}
/*
@@ -1589,27 +1580,52 @@
void mipi_dsi_cmdlist_commit(int from_mdp)
{
struct dcs_cmd_req *req;
+ int video;
+ u32 dsi_ctrl;
mutex_lock(&cmd_mutex);
req = mipi_dsi_cmdlist_get();
- if (req == NULL) {
- mutex_unlock(&cmd_mutex);
- return;
- }
+
+ /* make sure dsi_cmd_mdp is idle */
+ mipi_dsi_cmd_mdp_busy();
+
+ if (req == NULL)
+ goto need_lock;
+
+ video = MIPI_INP(MIPI_DSI_BASE + 0x0000);
+ video &= 0x02; /* VIDEO_MODE */
+
+ if (!video)
+ mipi_dsi_clk_cfg(1);
pr_debug("%s: from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid);
- if (!from_mdp) { /* from put */
- /* make sure dsi_cmd_mdp is idle */
- mipi_dsi_cmd_mdp_busy();
+ dsi_ctrl = MIPI_INP(MIPI_DSI_BASE + 0x0000);
+ if (dsi_ctrl & 0x02) {
+ /* video mode, make sure dsi_cmd_mdp is busy
+ * so dcs command will be txed at start of BLLP
+ */
+ mipi_dsi_wait_for_video_eng_busy();
+ } else {
+ /* command mode */
+ if (!from_mdp) { /* cmdlist_put */
+ /* make sure dsi_cmd_mdp is idle */
+ mipi_dsi_cmd_mdp_busy();
+ }
}
- mipi_dsi_clk_cfg(1);
if (req->flags & CMD_REQ_RX)
mipi_dsi_cmdlist_rx(req);
else
mipi_dsi_cmdlist_tx(req);
- mipi_dsi_clk_cfg(0);
+
+ if (!video)
+ mipi_dsi_clk_cfg(0);
+
+need_lock:
+
+ if (from_mdp) /* from pipe_commit */
+ mipi_dsi_cmd_mdp_start();
mutex_unlock(&cmd_mutex);
}
@@ -1762,8 +1778,8 @@
mipi_dsi_mdp_stat_inc(STAT_DSI_MDP);
spin_lock(&dsi_mdp_lock);
dsi_ctrl_lock = FALSE;
- mipi_dsi_disable_irq_nosync(DSI_MDP_TERM);
dsi_mdp_busy = FALSE;
+ mipi_dsi_disable_irq_nosync(DSI_MDP_TERM);
complete(&dsi_mdp_comp);
spin_unlock(&dsi_mdp_lock);
}
diff --git a/drivers/video/msm/mipi_novatek.c b/drivers/video/msm/mipi_novatek.c
index b893cc7..69ca0a3 100644
--- a/drivers/video/msm/mipi_novatek.c
+++ b/drivers/video/msm/mipi_novatek.c
@@ -302,19 +302,29 @@
static struct dsi_cmd_desc novatek_manufacture_id_cmd = {
DTYPE_DCS_READ, 1, 0, 1, 5, sizeof(manufacture_id), manufacture_id};
+static u32 manu_id;
+
+static void mipi_novatek_manufacture_cb(u32 data)
+{
+ manu_id = data;
+ pr_info("%s: manufacture_id=%x\n", __func__, manu_id);
+}
+
static uint32 mipi_novatek_manufacture_id(struct msm_fb_data_type *mfd)
{
- struct dsi_buf *rp, *tp;
- struct dsi_cmd_desc *cmd;
- uint32 *lp;
+ struct dcs_cmd_req cmdreq;
- tp = &novatek_tx_buf;
- rp = &novatek_rx_buf;
- cmd = &novatek_manufacture_id_cmd;
- mipi_dsi_cmds_rx(mfd, tp, rp, cmd, 3);
- lp = (uint32 *)rp->data;
- pr_info("%s: manufacture_id=%x\n", __func__, *lp);
- return *lp;
+ cmdreq.cmds = &novatek_manufacture_id_cmd;
+ cmdreq.cmds_cnt = 1;
+ cmdreq.flags = CMD_REQ_RX | CMD_REQ_COMMIT;
+ cmdreq.rlen = 3;
+ cmdreq.cb = mipi_novatek_manufacture_cb; /* call back */
+ mipi_dsi_cmdlist_put(&cmdreq);
+ /*
+ * blocked here, untill call back called
+ */
+
+ return manu_id;
}
static int fpga_addr;
@@ -380,6 +390,7 @@
struct msm_fb_data_type *mfd;
struct mipi_panel_info *mipi;
struct msm_panel_info *pinfo;
+ struct dcs_cmd_req cmdreq;
mfd = platform_get_drvdata(pdev);
if (!mfd)
@@ -394,23 +405,31 @@
mipi = &mfd->panel_info.mipi;
if (mipi->mode == DSI_VIDEO_MODE) {
- mipi_dsi_cmds_tx(&novatek_tx_buf, novatek_video_on_cmds,
- ARRAY_SIZE(novatek_video_on_cmds));
+ cmdreq.cmds = novatek_video_on_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(novatek_video_on_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
} else {
- mipi_dsi_cmds_tx(&novatek_tx_buf, novatek_cmd_on_cmds,
- ARRAY_SIZE(novatek_cmd_on_cmds));
+ cmdreq.cmds = novatek_cmd_on_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(novatek_cmd_on_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ mipi_dsi_cmdlist_put(&cmdreq);
/* clean up ack_err_status */
mipi_dsi_cmd_bta_sw_trigger();
mipi_novatek_manufacture_id(mfd);
}
-
return 0;
}
static int mipi_novatek_lcd_off(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
+ struct dcs_cmd_req cmdreq;
mfd = platform_get_drvdata(pdev);
@@ -419,8 +438,13 @@
if (mfd->key != MFD_KEY)
return -EINVAL;
- mipi_dsi_cmds_tx(&novatek_tx_buf, novatek_display_off_cmds,
- ARRAY_SIZE(novatek_display_off_cmds));
+ cmdreq.cmds = novatek_display_off_cmds;
+ cmdreq.cmds_cnt = ARRAY_SIZE(novatek_display_off_cmds);
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+
+ mipi_dsi_cmdlist_put(&cmdreq);
return 0;
}
@@ -431,10 +455,10 @@
static struct dsi_cmd_desc backlight_cmd = {
DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(led_pwm1), led_pwm1};
-struct dcs_cmd_req cmdreq;
static void mipi_novatek_set_backlight(struct msm_fb_data_type *mfd)
{
+ struct dcs_cmd_req cmdreq;
if ((mipi_novatek_pdata->enable_wled_bl_ctrl)
&& (wled_trigger_initialized)) {
@@ -446,7 +470,7 @@
cmdreq.cmds = &backlight_cmd;
cmdreq.cmds_cnt = 1;
- cmdreq.flags = 0;
+ cmdreq.flags = CMD_REQ_COMMIT;
cmdreq.rlen = 0;
cmdreq.cb = NULL;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
index d94bc5b..8cfa95b 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
@@ -274,8 +274,8 @@
}
vidc_sm_get_profile_info(&ddl->shared_mem
[ddl->command_channel], &disp_profile_info);
- disp_profile_info.pic_profile = seq_hdr_info.profile;
- disp_profile_info.pic_level = seq_hdr_info.level;
+ seq_hdr_info.profile = disp_profile_info.pic_profile;
+ seq_hdr_info.level = disp_profile_info.pic_level;
ddl_get_dec_profile_level(decoder, seq_hdr_info.profile,
seq_hdr_info.level);
switch (decoder->codec.codec) {
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 5b07403..98cce5b 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -445,3 +445,4 @@
header-y += genlock.h
header-y += msm_audio_amrwb.h
header-y += coresight-stm.h
+header-y += ci-bridge-spi.h
\ No newline at end of file
diff --git a/include/linux/ci-bridge-spi.h b/include/linux/ci-bridge-spi.h
new file mode 100644
index 0000000..1e531db
--- /dev/null
+++ b/include/linux/ci-bridge-spi.h
@@ -0,0 +1,17 @@
+#ifndef _CI_BRIDGE_SPI_H_
+#define _CI_BRIDGE_SPI_H_
+
+#include <linux/ioctl.h>
+
+#define CI_BRIDGE_IOCTL_MAGIC 'c'
+#define CI_BRIDGE_IOCTL_RESET _IOW(CI_BRIDGE_IOCTL_MAGIC, 0, unsigned)
+#define CI_BRIDGE_IOCTL_GET_INT_STATE _IOR(CI_BRIDGE_IOCTL_MAGIC, 1, unsigned)
+
+#ifdef __KERNEL__
+struct ci_bridge_platform_data {
+ unsigned int reset_pin;
+ unsigned int interrupt_pin;
+};
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index f0e42c2..bb5f394 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -18,14 +18,14 @@
#define EVENT_MASKS_TYPE 4
#define PKT_TYPE 8
#define DEINIT_TYPE 16
-#define USER_SPACE_LOG_TYPE 32
+#define USER_SPACE_DATA_TYPE 32
#define DCI_DATA_TYPE 64
#define USB_MODE 1
#define MEMORY_DEVICE_MODE 2
#define NO_LOGGING_MODE 3
#define UART_MODE 4
#define SOCKET_MODE 5
-
+#define CALLBACK_MODE 6
/* different values that go in for diag_data_type */
#define DATA_TYPE_EVENT 0
#define DATA_TYPE_F3 1
@@ -42,6 +42,7 @@
#define DIAG_IOCTL_DCI_SUPPORT 22
#define DIAG_IOCTL_DCI_REG 23
#define DIAG_IOCTL_DCI_STREAM_INIT 24
+#define DIAG_IOCTL_DCI_HEALTH_STATS 25
/* PC Tools IDs */
#define APQ8060_TOOLS_ID 4062
diff --git a/include/linux/dvb/video.h b/include/linux/dvb/video.h
index 2a2a53d..6c42099 100644
--- a/include/linux/dvb/video.h
+++ b/include/linux/dvb/video.h
@@ -151,6 +151,12 @@
struct video_buffer_prop output_buf_prop; /* Output Buffer Prop */
};
+enum scan_format {
+ INTERLACE_FRAME_PROGRESSIVE,
+ INTERLACE_INTERLEAVE_FRAME_TOP_FIELD_FIRST,
+ INTERLACE_INTERLEAVE_FRAME_BOTTOM_FIELD_FIRST
+};
+
/* Video Data Buffer Structure for Input and Output */
struct video_data_buffer {
void __user *bufferaddr; /* Pointer to Buffer */
@@ -161,6 +167,7 @@
void *client_data;
void *ip_buffer_tag;
__u64 pts;
+ enum scan_format interlaced_format;
};
struct video_h264_mv {
diff --git a/include/linux/i2c/smb350.h b/include/linux/i2c/smb350.h
new file mode 100644
index 0000000..5bb5cec
--- /dev/null
+++ b/include/linux/i2c/smb350.h
@@ -0,0 +1,35 @@
+/* Copyright (c) 2012 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful;
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __SMB350_H__
+#define __SMB350_H__
+
+#define SMB350_NAME "smb350"
+
+/**
+ * struct smb350_platform_data
+ * structure to pass board specific information to the smb137b charger driver
+ * @chg_current_ma: maximum fast charge current in mA
+ * @term_current_ma: charge termination current in mA
+ * @chg_en_n_gpio: gpio to enable or disable charging
+ * @chg_susp_n_gpio: put active low to allow chip to suspend and disable I2C
+ * @stat_gpio: STAT pin, active low, '0' when charging.
+ */
+struct smb350_platform_data {
+ int chg_en_n_gpio;
+ int chg_susp_n_gpio;
+ int chg_current_ma;
+ int term_current_ma;
+ int stat_gpio;
+};
+
+#endif
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 16d4a4b..130fb54 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -163,6 +163,7 @@
enum pm8921_chg_hot_thr hot_thr;
int rconn_mohm;
enum pm8921_chg_led_src_config led_src_config;
+ int battery_less_hardware;
};
enum pm8921_charger_source {
diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h
index c1ea490..ec043dd 100644
--- a/include/linux/msm_ion.h
+++ b/include/linux/msm_ion.h
@@ -1,6 +1,6 @@
/*
*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -39,8 +39,10 @@
ION_CP_MFC_HEAP_ID = 12,
ION_CP_WB_HEAP_ID = 16, /* 8660 only */
ION_CAMERA_HEAP_ID = 20, /* 8660 only */
+ ION_PIL1_HEAP_ID = 23, /* Currently used for other PIL images */
ION_SF_HEAP_ID = 24,
ION_IOMMU_HEAP_ID = 25,
+ ION_PIL2_HEAP_ID = 26, /* Currently used for modem firmware images */
ION_QSECOM_HEAP_ID = 27,
ION_AUDIO_HEAP_ID = 28,
@@ -86,6 +88,8 @@
#define ION_MFC_HEAP_NAME "mfc"
#define ION_WB_HEAP_NAME "wb"
#define ION_MM_FIRMWARE_HEAP_NAME "mm_fw"
+#define ION_PIL1_HEAP_NAME "pil_1"
+#define ION_PIL2_HEAP_NAME "pil_2"
#define ION_QSECOM_HEAP_NAME "qsecom"
#define ION_FMEM_HEAP_NAME "fmem"
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index f74db80..e5516ab 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -129,7 +129,7 @@
INTERNAL_RSENSE = 0,
EXTERNAL_RSENSE,
ALT_LEAD_PAIR,
- GAIN_CALIBRATION_25MV,
+ GAIN_CALIBRATION_17P857MV,
OFFSET_CALIBRATION_SHORT_CADC_LEADS,
OFFSET_CALIBRATION_CSP_CSN,
OFFSET_CALIBRATION_CSP2_CSN2,
@@ -590,13 +590,31 @@
* @channel - Channel for which the historical offset and gain is
* calculated. Available channels are internal rsense,
* external rsense and alternate lead pairs.
- * @offset - Offset value for the channel.
- * @gain - Gain of the channel.
+ * @offset_raw - raw Offset value for the channel.
+ * @gain_raw - raw Gain of the channel.
+ * @ideal_offset_uv - ideal offset value for the channel.
+ * @ideal_gain_nv - ideal gain for the channel.
+ * @offset_uv - converted value of offset in uV.
+ * @gain_uv - converted value of gain in uV.
*/
struct qpnp_iadc_calib {
enum qpnp_iadc_channels channel;
- int32_t offset;
- int32_t gain;
+ uint16_t offset_raw;
+ uint16_t gain_raw;
+ uint32_t ideal_offset_uv;
+ uint32_t ideal_gain_nv;
+ uint32_t offset_uv;
+ uint32_t gain_uv;
+};
+
+/**
+ * struct qpnp_iadc_result - IADC read result structure.
+ * @oresult_uv - Result of ADC in uV.
+ * @result_ua - Result of ADC in uA.
+ */
+struct qpnp_iadc_result {
+ int32_t result_uv;
+ int32_t result_ua;
};
/**
@@ -854,7 +872,7 @@
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
{ return -ENXIO; }
-static inline int32_t qpnp_vadc_is_read(void)
+static inline int32_t qpnp_vadc_is_ready(void)
{ return -ENXIO; }
#endif
@@ -867,23 +885,18 @@
* @result: Current across rsens in mV.
*/
int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
- int32_t *result);
+ struct qpnp_iadc_result *result);
/**
- * qpnp_iadc_get_gain() - Performs gain calibration over 25mV reference
- * across CCADC.
- * @result: Gain result across 25mV reference.
+ * qpnp_iadc_get_gain_and_offset() - Performs gain calibration
+ * over 17.8571mV and offset over selected
+ * channel. Channel can be internal rsense,
+ * external rsense and alternate lead pair.
+ * @result: result structure where the gain and offset is stored of
+ * type qpnp_iadc_calib.
*/
-int32_t qpnp_iadc_get_gain(int32_t *result);
+int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_calib *result);
/**
- * qpnp_iadc_get_offset() - Performs offset calibration over selected
- * channel. Channel can be internal rsense,
- * external rsense and alternate lead pair.
- * @result: Gain result across 25mV reference.
- */
-int32_t qpnp_iadc_get_offset(enum qpnp_iadc_channels channel,
- int32_t *result);
-/**
* qpnp_iadc_is_ready() - Clients can use this API to check if the
* device is ready to use.
* @result: 0 on success and -EPROBE_DEFER when probe for the device
@@ -892,14 +905,12 @@
int32_t qpnp_iadc_is_ready(void);
#else
static inline int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
- int *result)
+ struct qpnp_iadc_result *result)
{ return -ENXIO; }
-static inline int32_t qpnp_iadc_get_gain(int32_t *result)
+static inline int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_calib
+ *result)
{ return -ENXIO; }
-static inline int32_t qpnp_iadc_get_offset(enum qpnp_iadc_channels channel,
- int32_t *result)
-{ return -ENXIO; }
-static inline int32_t qpnp_iadc_is_read(void)
+static inline int32_t qpnp_iadc_is_ready(void)
{ return -ENXIO; }
#endif
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index 34464c6..0fd11a3 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -69,4 +69,5 @@
struct v4l2_event_subscription *sub);
int msm_vidc_dqevent(void *instance, struct v4l2_event *event);
int msm_vidc_wait(void *instance);
+int msm_vidc_s_parm(void *instance, struct v4l2_streamparm *a);
#endif
diff --git a/include/sound/compress_params.h b/include/sound/compress_params.h
index 02d69ea..f5c2d13 100644
--- a/include/sound/compress_params.h
+++ b/include/sound/compress_params.h
@@ -88,6 +88,7 @@
#define SND_AUDIOCODEC_DTS_TRANSCODE_LOOPBACK ((__u32) 0x00000014)
#define SND_AUDIOCODEC_PASS_THROUGH ((__u32) 0x00000015)
#define SND_AUDIOCODEC_MP2 ((__u32) 0x00000016)
+#define SND_AUDIOCODEC_DTS_LBR_PASS_THROUGH ((__u32) 0x00000017)
/*
* Profile and modes are listed with bit masks. This allows for a
* more compact representation of fields that will not evolve
diff --git a/mm/Kconfig b/mm/Kconfig
index 84489cd..4cde97f 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -379,3 +379,14 @@
in a negligible performance hit.
If unsure, say Y to enable cleancache
+
+config MEMORY_HOLE_CARVEOUT
+ bool
+ help
+ MEMORY_HOLE_CARVEOUT is needed to include the msm_mem_hole driver
+ which is needed to enable/disable memblock-remove features for
+ device tree nodes that set compatible="qcom,msm-mem-hole". The
+ corresponding device tree node provides the address and size of
+ the memory corresponding to the hole to be removed using memblock-
+ remove.
+
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 1703c37..95df162 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -978,10 +978,15 @@
"ZERO", "SRC1", "SRC2", "IIR1", "IIR2"
};
-static const char * const rx_dsm_text[] = {
- "CIC_OUT", "DSM_INV"
+static const char * const rx_rdac5_text[] = {
+ "DEM4", "DEM3_INV"
};
+static const char * const rx_rdac7_text[] = {
+ "DEM6", "DEM5_INV"
+};
+
+
static const char * const sb_tx1_mux_text[] = {
"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
"DEC1"
@@ -1135,11 +1140,11 @@
static const struct soc_enum rx7_mix2_inp2_chain_enum =
SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX7_B3_CTL, 3, 5, rx_mix2_text);
-static const struct soc_enum rx4_dsm_enum =
- SOC_ENUM_SINGLE(TAIKO_A_CDC_RX4_B6_CTL, 4, 2, rx_dsm_text);
+static const struct soc_enum rx_rdac5_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_MISC, 2, 2, rx_rdac5_text);
-static const struct soc_enum rx6_dsm_enum =
- SOC_ENUM_SINGLE(TAIKO_A_CDC_RX6_B6_CTL, 4, 2, rx_dsm_text);
+static const struct soc_enum rx_rdac7_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_MISC, 1, 2, rx_rdac7_text);
static const struct soc_enum sb_tx1_mux_enum =
SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
@@ -1280,11 +1285,11 @@
static const struct snd_kcontrol_new rx7_mix2_inp2_mux =
SOC_DAPM_ENUM("RX7 MIX2 INP2 Mux", rx7_mix2_inp2_chain_enum);
-static const struct snd_kcontrol_new rx4_dsm_mux =
- SOC_DAPM_ENUM("RX4 DSM MUX Mux", rx4_dsm_enum);
+static const struct snd_kcontrol_new rx_dac5_mux =
+ SOC_DAPM_ENUM("RDAC5 MUX Mux", rx_rdac5_enum);
-static const struct snd_kcontrol_new rx6_dsm_mux =
- SOC_DAPM_ENUM("RX6 DSM MUX Mux", rx6_dsm_enum);
+static const struct snd_kcontrol_new rx_dac7_mux =
+ SOC_DAPM_ENUM("RDAC7 MUX Mux", rx_rdac7_enum);
static const struct snd_kcontrol_new sb_tx1_mux =
SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
@@ -2635,15 +2640,18 @@
{"LINEOUT1 DAC", NULL, "RX3 MIX1"},
- {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
- {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
- {"LINEOUT3 DAC", NULL, "RX4 DSM MUX"},
+
+ {"RDAC5 MUX", "DEM3_INV", "RX3 MIX1"},
+ {"RDAC5 MUX", "DEM4", "RX4 MIX1"},
+
+ {"LINEOUT3 DAC", NULL, "RDAC5 MUX"},
{"LINEOUT2 DAC", NULL, "RX5 MIX1"},
- {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
- {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
- {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
+ {"RDAC7 MUX", "DEM5_INV", "RX5 MIX1"},
+ {"RDAC7 MUX", "DEM6", "RX6 MIX1"},
+
+ {"LINEOUT4 DAC", NULL, "RDAC7 MUX"},
{"SPK PA", NULL, "SPK DAC"},
{"SPK DAC", NULL, "RX7 MIX2"},
@@ -3844,13 +3852,6 @@
0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU),
- SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TAIKO_A_CDC_CLK_RX_B1_CTL, 3, 0,
- &rx4_dsm_mux, taiko_codec_enable_interpolator,
- SND_SOC_DAPM_PRE_PMU),
-
- SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TAIKO_A_CDC_CLK_RX_B1_CTL, 5, 0,
- &rx6_dsm_mux, taiko_codec_enable_interpolator,
- SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_MIXER("RX1 CHAIN", TAIKO_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
SND_SOC_DAPM_MIXER("RX2 CHAIN", TAIKO_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
@@ -3898,6 +3899,11 @@
SND_SOC_DAPM_MUX("RX7 MIX2 INP2", SND_SOC_NOPM, 0, 0,
&rx7_mix2_inp2_mux),
+ SND_SOC_DAPM_MUX("RDAC5 MUX", SND_SOC_NOPM, 0, 0,
+ &rx_dac5_mux),
+ SND_SOC_DAPM_MUX("RDAC7 MUX", SND_SOC_NOPM, 0, 0,
+ &rx_dac7_mux),
+
SND_SOC_DAPM_SUPPLY("CLASS_H_CLK", TAIKO_A_CDC_CLK_OTHR_CTL, 0, 0,
taiko_codec_enable_class_h_clk, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_PRE_PMD),
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index 69256363..016ef94 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -845,6 +845,21 @@
return 0;
}
+static int mpq8064_proxy_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ pr_debug("%s ()\n", __func__);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ return 0;
+}
+
static int msm_be_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -1570,6 +1585,7 @@
.codec_dai_name = "msm-stub-rx",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+ .be_hw_params_fixup = mpq8064_proxy_be_params_fixup,
.ignore_pmdown_time = 1, /* this dainlink has playback support */
},
{
@@ -1580,6 +1596,7 @@
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-tx",
.no_pcm = 1,
+ .be_hw_params_fixup = mpq8064_proxy_be_params_fixup,
.be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
},
/* AUX PCM Backend DAI Links */
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 8202982..eeabb78 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -382,6 +382,7 @@
break;
case SND_AUDIOCODEC_AC3_PASS_THROUGH:
case SND_AUDIOCODEC_DTS_PASS_THROUGH:
+ case SND_AUDIOCODEC_DTS_LBR_PASS_THROUGH:
pr_debug("compressd playback, no need to send decoder params");
pr_debug("decoder id: %d\n",
compr->info.codec_param.codec.id);
@@ -675,7 +676,7 @@
{
pr_debug("%s\n", __func__);
/* MP3 Block */
- compr->info.compr_cap.num_codecs = 13;
+ compr->info.compr_cap.num_codecs = 14;
compr->info.compr_cap.min_fragment_size = runtime->hw.period_bytes_min;
compr->info.compr_cap.max_fragment_size = runtime->hw.period_bytes_max;
compr->info.compr_cap.min_fragments = runtime->hw.periods_min;
@@ -693,6 +694,7 @@
compr->info.compr_cap.codecs[10] = SND_AUDIOCODEC_PASS_THROUGH;
compr->info.compr_cap.codecs[11] = SND_AUDIOCODEC_PCM;
compr->info.compr_cap.codecs[12] = SND_AUDIOCODEC_MP2;
+ compr->info.compr_cap.codecs[13] = SND_AUDIOCODEC_DTS_LBR_PASS_THROUGH;
/* Add new codecs here and update num_codecs*/
}
@@ -812,18 +814,19 @@
compressed_audio.prtd = NULL;
q6asm_audio_client_buf_free_contiguous(dir,
prtd->audio_client);
- if ((compr->info.codec_param.codec.id !=
- SND_AUDIOCODEC_AC3_PASS_THROUGH) &&
- (compr->info.codec_param.codec.id !=
- SND_AUDIOCODEC_DTS_PASS_THROUGH))
+ switch (compr->info.codec_param.codec.id) {
+ case SND_AUDIOCODEC_AC3_PASS_THROUGH:
+ case SND_AUDIOCODEC_DTS_PASS_THROUGH:
+ case SND_AUDIOCODEC_DTS_LBR_PASS_THROUGH:
+ msm_pcm_routing_reg_psthr_stream(
+ soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream,
+ 0);
+ default:
msm_pcm_routing_dereg_phy_stream(
soc_prtd->dai_link->be_id,
SNDRV_PCM_STREAM_PLAYBACK);
- else
- msm_pcm_routing_reg_psthr_stream(
- soc_prtd->dai_link->be_id,
- prtd->session_id, substream->stream,
- 0);
+ }
q6asm_audio_client_free(prtd->audio_client);
kfree(prtd);
return 0;
@@ -941,6 +944,7 @@
switch (compr->info.codec_param.codec.id) {
case SND_AUDIOCODEC_AC3_PASS_THROUGH:
case SND_AUDIOCODEC_DTS_PASS_THROUGH:
+ case SND_AUDIOCODEC_DTS_LBR_PASS_THROUGH:
ret = q6asm_open_write_compressed(prtd->audio_client,
compr->codec);
@@ -1139,6 +1143,10 @@
pr_debug("SND_AUDIOCODEC_DTS_PASS_THROUGH\n");
compr->codec = FORMAT_DTS;
break;
+ case SND_AUDIOCODEC_DTS_LBR_PASS_THROUGH:
+ pr_debug("SND_AUDIOCODEC_DTS_LBR_PASS_THROUGH\n");
+ compr->codec = FORMAT_DTS_LBR;
+ break;
case SND_AUDIOCODEC_DTS: {
char modelId[128];
struct snd_dec_dts opt_dts =
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 7e70d02..b7d5d33 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -896,10 +896,11 @@
case ASM_STREAM_CMD_OPEN_READ_COMPRESSED:
if (atomic_read(&ac->cmd_state) && wakeup_flag) {
atomic_set(&ac->cmd_state, 0);
+ pr_debug("response payload[1]:%d",
+ payload[1]);
if (payload[1] == ADSP_EUNSUPPORTED ||
+ payload[1] == ADSP_EBADPARAM ||
payload[1] == ADSP_EFAILED) {
- pr_debug("payload[1]:%d unsupported",
- payload[1]);
atomic_set(&ac->cmd_response, 1);
}
else
@@ -1485,6 +1486,10 @@
rc);
goto fail_cmd;
}
+ if (atomic_read(&ac->cmd_response)) {
+ pr_err("%s: format = %x not supported\n", __func__, format);
+ goto fail_cmd;
+ }
return 0;
fail_cmd:
return -EINVAL;
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index dc851ce..915c3c2 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1496,9 +1496,6 @@
struct snd_soc_dpcm_params *dpcm_params;
int ret = 0;
- if ((cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) ||
- (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH))
- return ret;
list_for_each_entry(dpcm_params, &fe->dpcm[stream].be_clients, list_be) {
@@ -1767,6 +1764,7 @@
if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
continue;