Merge "msm: pm-8x60: Remove enum from devicetree"
diff --git a/Documentation/ABI/testing/sysfs-devices-power b/Documentation/ABI/testing/sysfs-devices-power
index b0a5d9a..45000f0 100644
--- a/Documentation/ABI/testing/sysfs-devices-power
+++ b/Documentation/ABI/testing/sysfs-devices-power
@@ -158,6 +158,17 @@
not enabled to wake up the system from sleep states, this
attribute is not present.
+What: /sys/devices/.../power/wakeup_prevent_sleep_time_ms
+Date: February 2012
+Contact: Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+ The /sys/devices/.../wakeup_prevent_sleep_time_ms attribute
+ contains the total time the device has been preventing
+ opportunistic transitions to sleep states from occuring.
+ This attribute is read-only. If the device is not enabled to
+ wake up the system from sleep states, this attribute is not
+ present.
+
What: /sys/devices/.../power/autosuspend_delay_ms
Date: September 2010
Contact: Alan Stern <stern@rowland.harvard.edu>
diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power
index b464d12..31725ff 100644
--- a/Documentation/ABI/testing/sysfs-power
+++ b/Documentation/ABI/testing/sysfs-power
@@ -172,3 +172,62 @@
Reading from this file will display the current value, which is
set to 1 MB by default.
+
+What: /sys/power/autosleep
+Date: April 2012
+Contact: Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+ The /sys/power/autosleep file can be written one of the strings
+ returned by reads from /sys/power/state. If that happens, a
+ work item attempting to trigger a transition of the system to
+ the sleep state represented by that string is queued up. This
+ attempt will only succeed if there are no active wakeup sources
+ in the system at that time. After every execution, regardless
+ of whether or not the attempt to put the system to sleep has
+ succeeded, the work item requeues itself until user space
+ writes "off" to /sys/power/autosleep.
+
+ Reading from this file causes the last string successfully
+ written to it to be returned.
+
+What: /sys/power/wake_lock
+Date: February 2012
+Contact: Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+ The /sys/power/wake_lock file allows user space to create
+ wakeup source objects and activate them on demand (if one of
+ those wakeup sources is active, reads from the
+ /sys/power/wakeup_count file block or return false). When a
+ string without white space is written to /sys/power/wake_lock,
+ it will be assumed to represent a wakeup source name. If there
+ is a wakeup source object with that name, it will be activated
+ (unless active already). Otherwise, a new wakeup source object
+ will be registered, assigned the given name and activated.
+ If a string written to /sys/power/wake_lock contains white
+ space, the part of the string preceding the white space will be
+ regarded as a wakeup source name and handled as descrived above.
+ The other part of the string will be regarded as a timeout (in
+ nanoseconds) such that the wakeup source will be automatically
+ deactivated after it has expired. The timeout, if present, is
+ set regardless of the current state of the wakeup source object
+ in question.
+
+ Reads from this file return a string consisting of the names of
+ wakeup sources created with the help of it that are active at
+ the moment, separated with spaces.
+
+
+What: /sys/power/wake_unlock
+Date: February 2012
+Contact: Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+ The /sys/power/wake_unlock file allows user space to deactivate
+ wakeup sources created with the help of /sys/power/wake_lock.
+ When a string is written to /sys/power/wake_unlock, it will be
+ assumed to represent the name of a wakeup source to deactivate.
+ If a wakeup source object of that name exists and is active at
+ the moment, it will be deactivated.
+
+ Reads from this file return a string consisting of the names of
+ wakeup sources created with the help of /sys/power/wake_lock
+ that are inactive at the moment, separated with spaces.
diff --git a/Documentation/devicetree/bindings/arm/msm/mpm_counter.txt b/Documentation/devicetree/bindings/arm/msm/mpm_counter.txt
index e62b9ec..9ac1cbd 100644
--- a/Documentation/devicetree/bindings/arm/msm/mpm_counter.txt
+++ b/Documentation/devicetree/bindings/arm/msm/mpm_counter.txt
@@ -1,4 +1,4 @@
-* MSM Timetick counter (mpm-v2)
+* MSM MPM sleep counter (mpm-v2)
The MPM provides a timetick that starts when the device is powered up and
is not reset by any of the boot loaders or the HLOS. The MPM timetick counter
@@ -6,12 +6,14 @@
The required nodes for the MPM timetick counter driver are:
-- compatible: "qcom,mpm-counter"
+- compatible: "qcom,mpm2-sleep-counter"
- reg: Specifies the physical address of the timetick count register.
+- clock-frequency: the physical counter frequency.
Example:
- qcom,mpm-counter@fc4a3000 {
- compatible = "qcom,mpm-counter";
+ qcom,mpm2-sleep-counter@fc4a3000 {
+ compatible = "qcom,mpm2-sleep-counter";
reg = <0xfc4a3000 0x1000>;
+ clock-frequency = <32768>;
};
diff --git a/Documentation/devicetree/bindings/arm/msm/pmu.txt b/Documentation/devicetree/bindings/arm/msm/pmu.txt
new file mode 100644
index 0000000..0bd5e58
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/pmu.txt
@@ -0,0 +1,40 @@
+* Qcom Performance Monitor Units
+Qcom cores have several PMUs for counting CPU side, L2 and bus side events.
+
+For the L1CC PMU:
+In most cases the L1 cache controller PMU is a per cpu unit. The irq-is-percpu
+flag becomes a requirement if this is the case.
+
+Required Properties:
+
+- compatible : Should be "qcom,krait-pmu"
+- interrupts : 1 combined interrupt or 1 per core. See the devicetree/bindings/gic.txt for more details on this format.
+
+Optional:
+
+- qcom,irq-is-percpu: Define this if the IRQ of the PMU is a PPI. This will tell perf to use
+ the per_cpu IRQ API for request and free.
+
+Example:
+
+ arm-pmu {
+ compatible = "qcom,krait-pmu";
+ qcom,irq-is-percpu;
+ interrupts = <1 7 0xf00>;
+ };
+
+For the L2CC PMU:
+If the L2 cache controller PMU is available, its DT bindings should be defined as
+follows.
+
+Required Properties:
+
+- compatible: Should be "qcom,l2-pmu"
+- interrupts : 1 combined interrupt.
+
+Example:
+
+ l2-pmu {
+ compatible = "qcom,l2-pmu";
+ interrupts = <0 1 0>;
+ };
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index a432fb5..9a7fa90 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -39,8 +39,7 @@
Required properties:
- compatible : should be "qcom" followed by sensor name
- "qcom,s5k3l1yx"
-- reg : should contain i2c slave address of the camera sensor and
- length of data field which is 0x0
+- reg : should contain i2c slave address of the device
- qcom,slave-id : should contain i2c slave address, device id address
and expected id read value
- qcom,csiphy-sd-index : should contain csiphy instance that will used to
@@ -176,14 +175,14 @@
actuator0: qcom,actuator@18 {
cell-index = <0>;
- reg = <0x18 0x0>;
+ reg = <0x18>;
compatible = "qcom,actuator";
qcom,cci-master = <0>;
};
qcom,s5k3l1yx@6e {
compatible = "qcom,s5k3l1yx";
- reg = <0x6e 0x0>;
+ reg = <0x6e>;
qcom,slave-id = <0x6e 0x0 0x3121>;
qcom,csiphy-sd-index = <2>;
qcom,csid-sd-index = <0>;
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index a0c7037..d5937cf 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -20,6 +20,24 @@
Optional Properties:
- interrupt-names - "status_irq". This status_irq will be used for card
detection.
+ - cd-gpios: specify GPIO for card detection. If this property is
+ defined, then it means SDHC device has more than one interrupt
+ parent and hence, it is required to define the following properties
+ to configure interrupts from multiple parents -
+
+ interrupt-parent - This must provide reference to the current
+ device node.
+ #address-cells - Should provide a value of 0.
+ interrupts - Should be <0 1 2> and it is an index to the
+ interrupt-map.
+ #interrupt-cells - should provide a value of 1.
+ #interrupt-mask - should provide a value of 0xffffffff.
+ interrupt-map - Must create mapping for the number of interrupts
+ that are defined in above interrupts property.
+ For SDHC device node, it must define 3 mappings for
+ hc_irq, pwr_irq and status_irq in the format
+ mentioned in below example node of sdhc_2.
+
- qcom,bus-width - defines the bus I/O width that controller supports.
Units - number of bits. The valid bus-width values are
1, 4 and 8.
@@ -109,8 +127,17 @@
compatible = "qcom,sdhci-msm";
reg = <0xf9824900 0x11c>, <0xf9824000 0x800>;
reg-names = "hc_mem", "core_mem";
- interrupts = <0 123 0>, <0 138 0>;
- interrupt-names = "hc_irq", "pwr_irq";
+
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0
+ 2 &msmgpio 62 0x3>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&msmgpio 62 0x1>;
vdd-supply = <&pm8941_l21>;
vdd-io-supply = <&pm8941_l13>;
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-coincell.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-coincell.txt
new file mode 100644
index 0000000..10c1bbf
--- /dev/null
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-coincell.txt
@@ -0,0 +1,44 @@
+Qualcomm QPNP Coincell - coincell battery charger devices
+
+Required properties:
+- compatible: Must be "qcom,qpnp-coincell".
+- reg: Specifies the SPMI address and size for this coincell device.
+
+Required structure:
+- A qcom,qpnp-coincell node must be a child of an SPMI node that has specified
+ the spmi-slave-container property.
+
+Optional properties:
+- qcom,rset-ohms: Specifies the resistance of the current limiting
+ resistor in ohms. Four values are supported:
+ 800, 1200, 1700, and 2100.
+- qcom,vset-millivolts: Specifies the coincell charging voltage in millivolts.
+ Four values are supported: 2500, 3000, 3100, and 3200.
+- qcom,charge-enable: Specifies if coincell charging should be enabled or not.
+ 0 = disable charging, 1 = enabled charging
+
+If any of the optional properties are not specified, then the hardware default
+values for the unspecified properties will be used instead.
+
+Example:
+ qcom,spmi@fc4c0000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+
+ qcom,pm8941@1 {
+ spmi-slave-container;
+ reg = <0x1>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ qcom,coincell@2800 {
+ compatible = "qcom,qpnp-coincell";
+ reg = <0x2800 0x100>;
+ qcom,rset-ohms = <800>;
+ qcom,vset-millivolts = <3100>;
+ qcom,charge-enable = <1>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index 4590227..2832693 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -26,16 +26,17 @@
- qcom,chg-vddmax-mv: Target voltage of battery in mV.
- qcom,chg-vddsafe-mv: Maximum Vdd voltage in mV.
- qcom,chg-vinmin-mv: Minimum input voltage in mV.
-- qcom,chg-vbatdet-mv: Battery charging resume voltage in mV.
- qcom,chg-ibatmax-ma: Maximum battery charge current in mA
-- qcom,chg-ibatterm-ma: Current at which charging is terminated.
- qcom,chg-ibatsafe-ma: Safety battery current setting
- qcom,chg-thermal-mitigation: Array of ibatmax values for different
system thermal mitigation level.
Parent node optional properties:
+- qcom,chg-ibatterm-ma: Current at which charging is terminated when
+ the analog end of charge option is selected.
- qcom,chg-maxinput-usb-ma: Maximum input current USB.
- qcom,chg-maxinput-dc-ma: Maximum input current DC.
+- qcom,chg-vbatdet-delta-mv: Battery charging resume delta.
- qcom,chg-charging-disabled: Set this property to disable charging
by default. This can then be overriden
writing the the module parameter
@@ -44,6 +45,16 @@
battery temperature of 250 decidegree
Celsius, state of charge to be 50%
and disable charging.
+- qcom,chg-warm-bat-degc: Warm battery temperature in degC.
+- qcom,chg-cool-bat-degc: Cool battery temperature in degC.
+ Note that if both warm and cool battery
+ temperatures are set, the corresponding
+ ibatmax and bat-mv properties are
+ required to be set.
+- qcom,chg-ibatmax-cool-ma: Maximum cool battery charge current.
+- qcom,chg-ibatmax-warm-ma: Maximum warm battery charge current.
+- qcom,chg-warm-bat-mv: Warm temperature battery target voltage.
+- qcom,chg-cool-bat-mv: Cool temperature battery target voltage.
Sub node required structure:
- A qcom,chg node must be a child of an SPMI node that has specified
@@ -132,11 +143,17 @@
qcom,chg-vddmax-mv = <4200>;
qcom,chg-vddsafe-mv = <4200>;
qcom,chg-vinmin-mv = <4200>;
- qcom,chg-vbatdet-mv = <4200>;
qcom,chg-ibatmax-ma = <1500>;
qcom,chg-ibatterm-ma = <200>;
qcom,chg-ibatsafe-ma = <1500>;
qcom,chg-thermal-mitigation = <1500 700 600 325>;
+ qcom,chg-cool-bat-degc = <10>;
+ qcom,chg-cool-bat-mv = <4100>;
+ qcom,chg-ibatmax-warm-ma = <350>;
+ qcom,chg-warm-bat-degc = <45>;
+ qcom,chg-warm-bat-mv = <4100>;
+ qcom,chg-ibatmax-cool-ma = <350>;
+ qcom,chg-vbatdet-delta-mv = <60>;
qcom,chg-chgr@1000 {
reg = <0x1000 0x100>;
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index ffb0c6a..1885e8a 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -5,11 +5,14 @@
- regs : offset and length of the register set in the memory map
- interrupts: IRQ lines used by this controller
- interrupt-names : Required interrupt resource entries are:
- HSIC EHCI expects "core_irq" and optionally "async_irq".
+ "core_irq" : Interrupt for HSIC core
- <supply-name>-supply: handle to the regulator device tree node
Required "supply-name" is "HSIC_VDDCX" and optionally - "HSIC_GDSC".
Optional properties :
+- interrupt-names : Optional interrupt resource entries are:
+ "async_irq" : Interrupt from HSIC for asynchronous events in HSIC LPM.
+ "wakeup" : Wakeup interrupt from HSIC during suspend (or XO shutdown).
- hsic,<gpio-name>-gpio : handle to the GPIO node, see "gpios property"
in Documentation/devicetree/bindings/gpio/gpio.txt.
Optional "gpio-name" can be "strobe" and "data".
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 6cf59ee..df88caa 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -114,6 +114,7 @@
- qcom,usb2-enable-hsphy2: If present, select second PHY for USB operation.
- qcom,pool-64-bit-align: If present then the pool's memory will be aligned
to 64 bits
+- qcom,enable_hbm: if present host bus manager is enabled.
Example MSM HSUSB EHCI controller device node :
ehci: qcom,ehci-host@f9a55000 {
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
new file mode 100644
index 0000000..f09a78a
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
@@ -0,0 +1,159 @@
+/* Copyright (c) 2013, 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.
+ */
+
+/ {
+ qcom,mdss_dsi_nt35590_720p_video {
+ compatible = "qcom,mdss-dsi-panel";
+ label = "nt35590 720p video mode dsi panel";
+ status = "disable";
+ qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
+ qcom,rst-gpio = <&msmgpio 25 0>;
+ qcom,mdss-pan-res = <720 1280>;
+ qcom,mdss-pan-bpp = <24>;
+ qcom,mdss-pan-dest = "display_1";
+ qcom,mdss-pan-porch-values = <164 8 140 1 1 6>;
+ qcom,mdss-pan-underflow-clr = <0xff>;
+ qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
+ qcom,mdss-pan-bl-levels = <1 255>;
+ qcom,mdss-pan-dsi-mode = <0>;
+ qcom,mdss-pan-dsi-h-pulse-mode = <1>;
+ qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
+ qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
+ qcom,mdss-pan-dsi-traffic-mode = <2>;
+ qcom,mdss-pan-dsi-dst-format = <3>;
+ qcom,mdss-pan-dsi-vc = <0>;
+ qcom,mdss-pan-dsi-rgb-swap = <0>;
+ qcom,mdss-pan-dsi-data-lanes = <1 1 1 1>; /* 4 lanes */
+ qcom,mdss-pan-dsi-dlane-swap = <0>;
+ qcom,mdss-pan-dsi-t-clk = <0x2c 0x20>;
+ qcom,mdss-pan-dsi-stream = <0>;
+ qcom,mdss-pan-dsi-mdp-tr = <0x0>;
+ qcom,mdss-pan-dsi-dma-tr = <0x04>;
+ qcom,mdss-pan-frame-rate = <60>;
+ qcom,panel-phy-regulatorSettings = [07 09 03 00 /* Regualotor settings */
+ 20 00 01];
+ qcom,panel-phy-timingSettings = [7d 25 1d 00 37 33
+ 22 27 1e 03 04 00];
+ qcom,panel-phy-strengthCtrl = [ff 06];
+ qcom,panel-phy-bistCtrl = [00 00 b1 ff /* BIST Ctrl settings */
+ 00 00];
+ qcom,panel-phy-laneConfig = [00 00 00 00 00 00 00 01 97 /* lane0 config */
+ 00 00 00 00 05 00 00 01 97 /* lane1 config */
+ 00 00 00 00 0a 00 00 01 97 /* lane2 config */
+ 00 00 00 00 0f 00 00 01 97 /* lane3 config */
+ 00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
+ qcom,panel-on-cmds = [29 01 00 00 00 02 FF EE
+ 29 01 00 00 00 02 26 08
+ 29 01 00 00 00 02 26 00
+ 29 01 00 00 10 02 FF 00
+ 29 01 00 00 00 02 BA 03
+ 29 01 00 00 00 02 C2 03
+ 29 01 00 00 00 02 FF 01
+ 29 01 00 00 00 02 FB 01
+ 29 01 00 00 00 02 00 4A
+ 29 01 00 00 00 02 01 33
+ 29 01 00 00 00 02 02 53
+ 29 01 00 00 00 02 03 55
+ 29 01 00 00 00 02 04 55
+ 29 01 00 00 00 02 05 33
+ 29 01 00 00 00 02 06 22
+ 29 01 00 00 00 02 08 56
+ 29 01 00 00 00 02 09 8F
+ 29 01 00 00 00 02 36 73
+ 29 01 00 00 00 02 0B 9F
+ 29 01 00 00 00 02 0C 9F
+ 29 01 00 00 00 02 0D 2F
+ 29 01 00 00 00 02 0E 24
+ 29 01 00 00 00 02 11 83
+ 29 01 00 00 00 02 12 03
+ 29 01 00 00 00 02 71 2C
+ 29 01 00 00 00 02 6F 03
+ 29 01 00 00 00 02 0F 0A
+ 29 01 00 00 00 02 FF 05
+ 29 01 00 00 00 02 FB 01
+ 29 01 00 00 00 02 01 00
+ 29 01 00 00 00 02 02 8B
+ 29 01 00 00 00 02 03 82
+ 29 01 00 00 00 02 04 82
+ 29 01 00 00 00 02 05 30
+ 29 01 00 00 00 02 06 33
+ 29 01 00 00 00 02 07 01
+ 29 01 00 00 00 02 08 00
+ 29 01 00 00 00 02 09 46
+ 29 01 00 00 00 02 0A 46
+ 29 01 00 00 00 02 0D 0B
+ 29 01 00 00 00 02 0E 1D
+ 29 01 00 00 00 02 0F 08
+ 29 01 00 00 00 02 10 53
+ 29 01 00 00 00 02 11 00
+ 29 01 00 00 00 02 12 00
+ 29 01 00 00 00 02 14 01
+ 29 01 00 00 00 02 15 00
+ 29 01 00 00 00 02 16 05
+ 29 01 00 00 00 02 17 00
+ 29 01 00 00 00 02 19 7F
+ 29 01 00 00 00 02 1A FF
+ 29 01 00 00 00 02 1B 0F
+ 29 01 00 00 00 02 1C 00
+ 29 01 00 00 00 02 1D 00
+ 29 01 00 00 00 02 1E 00
+ 29 01 00 00 00 02 1F 07
+ 29 01 00 00 00 02 20 00
+ 29 01 00 00 00 02 21 06
+ 29 01 00 00 00 02 22 55
+ 29 01 00 00 00 02 23 4D
+ 29 01 00 00 00 02 2D 02
+ 29 01 00 00 00 02 28 01
+ 29 01 00 00 00 02 2F 02
+ 29 01 00 00 00 02 83 01
+ 29 01 00 00 00 02 9E 58
+ 29 01 00 00 00 02 9F 6A
+ 29 01 00 00 00 02 A0 01
+ 29 01 00 00 00 02 A2 10
+ 29 01 00 00 00 02 BB 0A
+ 29 01 00 00 00 02 BC 0A
+ 29 01 00 00 00 02 32 08
+ 29 01 00 00 00 02 33 B8
+ 29 01 00 00 00 02 36 01
+ 29 01 00 00 00 02 37 00
+ 29 01 00 00 00 02 43 00
+ 29 01 00 00 00 02 4B 21
+ 29 01 00 00 00 02 4C 03
+ 29 01 00 00 00 02 50 21
+ 29 01 00 00 00 02 51 03
+ 29 01 00 00 00 02 58 21
+ 29 01 00 00 00 02 59 03
+ 29 01 00 00 00 02 5D 21
+ 29 01 00 00 00 02 5E 03
+ 29 01 00 00 00 02 6C 00
+ 29 01 00 00 00 02 6D 00
+ 29 01 00 00 00 02 FF 01
+ 29 01 00 00 00 02 FB 01
+ 29 01 00 00 00 02 FF 02
+ 29 01 00 00 00 02 FB 01
+ 29 01 00 00 00 02 FF 04
+ 29 01 00 00 00 02 FB 01
+ 29 01 00 00 00 02 FF 00
+ 29 01 00 00 64 02 11 00
+ 29 01 00 00 00 02 FF EE
+ 29 01 00 00 00 02 12 50
+ 29 01 00 00 00 02 13 02
+ 29 01 00 00 00 02 6A 60
+ 29 01 00 00 00 02 FF 00
+ 29 01 00 00 78 02 29 00];
+
+ qcom,on-cmds-dsi-state = "DSI_LP_MODE";
+ qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
+ 05 01 00 00 78 02 10 00];
+ qcom,off-cmds-dsi-state = "DSI_HS_MODE";
+ };
+};
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 94db3ea..2f58185 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -15,4 +15,18 @@
#size-cells = <0>;
interrupt-controller;
#interrupt-cells = <3>;
+
+ qcom,pm8110@0 {
+ spmi-slave-container;
+ reg = <0x0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
+
+ qcom,pm8110@1 {
+ spmi-slave-container;
+ reg = <0x1>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
};
diff --git a/arch/arm/boot/dts/msm-pm8226-rpm-regulator.dtsi b/arch/arm/boot/dts/msm-pm8226-rpm-regulator.dtsi
new file mode 100644
index 0000000..ded9494
--- /dev/null
+++ b/arch/arm/boot/dts/msm-pm8226-rpm-regulator.dtsi
@@ -0,0 +1,492 @@
+/* Copyright (c) 2013, 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.
+ */
+
+&rpm_bus {
+ rpm-regulator-smpa1 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <1>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s1 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_s1";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa3 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <3>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s3 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_s3";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa4 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <4>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s4 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_s4";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa5 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <5>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s5 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_s5";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa1 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <1>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l1 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l1";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa2 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <2>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l2 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l2";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa3 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <3>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l3 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l3";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa4 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <4>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l4 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l4";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa5 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <5>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l5 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l5";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa6 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <6>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l6 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l6";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa7 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <7>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l7 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l7";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa8 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <8>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <5000>;
+ status = "disabled";
+
+ regulator-l8 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l8";
+ qcom,set = <1>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa9 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <9>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l9 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l9";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa10 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <10>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <5000>;
+ status = "disabled";
+
+ regulator-l10 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l10";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa12 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <12>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l12 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l12";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa14 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <14>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <5000>;
+ status = "disabled";
+
+ regulator-l14 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l14";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa15 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <15>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l15 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l15";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa16 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <16>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l16 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l16";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa17 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <17>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l17 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l17";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa18 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <18>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l18 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l18";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa19 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <19>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l19 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l19";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa20 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <20>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <5000>;
+ status = "disabled";
+
+ regulator-l20 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l20";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa21 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <21>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <5000>;
+ status = "disabled";
+
+ regulator-l21 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l21";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa22 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <22>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l22 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l22";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa23 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <23>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l23 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l23";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa24 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <24>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l24 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l24";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa26 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <26>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l26 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l26";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa27 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <27>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l27 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l27";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa28 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <28>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l28 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l28";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-vsa1 {
+ compatible = "qcom,rpm-regulator-smd-resource";
+ qcom,resource-name = "vsa";
+ qcom,resource-id = <1>;
+ qcom,regulator-type = <2>;
+ status = "disabled";
+
+ regulator-lvs1 {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_lvs1";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 28ca985..d456303 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -85,6 +85,11 @@
qcom,sample-rate = <4>;
};
+ pm8941_coincell: qcom,coincell@2800 {
+ compatible = "qcom,qpnp-coincell";
+ reg = <0x2800 0x100>;
+ };
+
pm8941_bms: qcom,bms {
spmi-dev-container;
compatible = "qcom,qpnp-bms";
@@ -161,11 +166,16 @@
qcom,chg-vddmax-mv = <4200>;
qcom,chg-vddsafe-mv = <4200>;
qcom,chg-vinmin-mv = <4200>;
- qcom,chg-vbatdet-mv = <4100>;
qcom,chg-ibatmax-ma = <1500>;
- qcom,chg-ibatterm-ma = <200>;
qcom,chg-ibatsafe-ma = <1500>;
qcom,chg-thermal-mitigation = <1500 700 600 325>;
+ qcom,chg-cool-bat-degc = <10>;
+ qcom,chg-cool-bat-mv = <4100>;
+ qcom,chg-ibatmax-warm-ma = <350>;
+ qcom,chg-warm-bat-degc = <45>;
+ qcom,chg-warm-bat-mv = <4100>;
+ qcom,chg-ibatmax-cool-ma = <350>;
+ qcom,chg-vbatdet-delta-mv = <350>;
qcom,chg-chgr@1000 {
status = "disabled";
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
index 5cb68e5..ec4b464b 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -12,6 +12,7 @@
/dts-v1/;
/include/ "msm8226.dtsi"
+/include/ "dsi-panel-nt35590-720p-video.dtsi"
/ {
model = "Qualcomm MSM 8226 CDP";
@@ -22,6 +23,10 @@
status = "ok";
};
+ qcom,mdss_dsi_nt35590_720p_video {
+ status = "ok";
+ };
+
i2c@f9927000 { /* BLSP1 QUP5 */
synaptics@20 {
compatible = "synaptics,rmi4";
@@ -69,6 +74,19 @@
debounce-interval = <15>;
};
};
+
+ spi@f9923000 {
+ ethernet-switch@3 {
+ compatible = "micrel,ks8851";
+ reg = <3>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <0 115 0>;
+ spi-max-frequency = <4800000>;
+ rst-gpio = <&msmgpio 114 0>;
+ vdd-io-supply = <&pm8226_lvs1>;
+ vdd-phy-supply = <&pm8226_lvs1>;
+ };
+ };
};
&sdcc1 {
diff --git a/arch/arm/boot/dts/msm8226-iommu.dtsi b/arch/arm/boot/dts/msm8226-iommu.dtsi
index bddafc9..460068b 100644
--- a/arch/arm/boot/dts/msm8226-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8226-iommu.dtsi
@@ -14,6 +14,7 @@
&jpeg_iommu {
status = "ok";
+ qcom,iommu-enable-halt;
qcom,iommu-bfb-regs = <0x204c
0x2050
@@ -50,6 +51,7 @@
&mdp_iommu {
status = "ok";
+ qcom,iommu-enable-halt;
qcom,iommu-bfb-regs = <0x204c
0x2050
@@ -92,6 +94,7 @@
&venus_iommu {
status = "ok";
+ qcom,iommu-enable-halt;
qcom,iommu-bfb-regs = <0x204c
0x2050
@@ -154,6 +157,7 @@
&kgsl_iommu {
status = "ok";
+ qcom,iommu-enable-halt;
qcom,iommu-bfb-regs = <0x204c
0x2050
@@ -184,6 +188,7 @@
&vfe_iommu {
status = "ok";
+ qcom,iommu-enable-halt;
qcom,iommu-bfb-regs = <0x204c
0x2050
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 1691743..30a89ef 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -53,6 +53,17 @@
};
};
+ mdss_dsi0: qcom,mdss_dsi@fd922800 {
+ compatible = "qcom,mdss-dsi-ctrl";
+ label = "MDSS DSI CTRL->0";
+ cell-index = <0>;
+ reg = <0xfd922800 0x600>;
+ vdd-supply = <&pm8226_l15>;
+ vdd_io-supply = <&pm8226_l8>;
+ vreg-supply = <&pm8226_l4>;
+ qcom,mdss-fb-map = <&mdss_fb0>;
+ };
+
qcom,mdss_wb_panel {
compatible = "qcom,mdss_wb";
qcom,mdss_pan_res = <1280 720>;
diff --git a/arch/arm/boot/dts/msm8226-mtp.dts b/arch/arm/boot/dts/msm8226-mtp.dts
index 07441d8..57fb4b5 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-mtp.dts
@@ -12,6 +12,7 @@
/dts-v1/;
/include/ "msm8226.dtsi"
+/include/ "dsi-panel-nt35590-720p-video.dtsi"
/ {
model = "Qualcomm MSM 8226 MTP";
@@ -22,6 +23,10 @@
status = "ok";
};
+ qcom,mdss_dsi_nt35590_720p_video {
+ status = "ok";
+ };
+
i2c@f9927000 { /* BLSP1 QUP5 */
synaptics@20 {
compatible = "synaptics,rmi4";
@@ -69,6 +74,19 @@
debounce-interval = <15>;
};
};
+
+ spi@f9923000 {
+ ethernet-switch@3 {
+ compatible = "micrel,ks8851";
+ reg = <3>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <0 115 0>;
+ spi-max-frequency = <4800000>;
+ rst-gpio = <&msmgpio 114 0>;
+ vdd-io-supply = <&pm8226_lvs1>;
+ vdd-phy-supply = <&pm8226_lvs1>;
+ };
+ };
};
&sdcc1 {
diff --git a/arch/arm/boot/dts/msm8226-qrd.dts b/arch/arm/boot/dts/msm8226-qrd.dts
index cdb2680..09b2d0b 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-qrd.dts
@@ -12,6 +12,7 @@
/dts-v1/;
/include/ "msm8226.dtsi"
+/include/ "dsi-panel-nt35590-720p-video.dtsi"
/ {
model = "Qualcomm MSM 8226 QRD";
@@ -22,6 +23,10 @@
status = "ok";
};
+ qcom,mdss_dsi_nt35590_720p_video {
+ status = "ok";
+ };
+
i2c@f9927000 { /* BLSP1 QUP5 */
synaptics@20 {
compatible = "synaptics,rmi4";
@@ -69,6 +74,19 @@
debounce-interval = <15>;
};
};
+
+ spi@f9923000 {
+ ethernet-switch@3 {
+ compatible = "micrel,ks8851";
+ reg = <3>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <0 115 0>;
+ spi-max-frequency = <4800000>;
+ rst-gpio = <&msmgpio 114 0>;
+ vdd-io-supply = <&pm8226_lvs1>;
+ vdd-phy-supply = <&pm8226_lvs1>;
+ };
+ };
};
&sdcc1 {
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 8168826..c39d987 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -10,300 +10,374 @@
* GNU General Public License for more details.
*/
-/* Stub Regulators */
-
-/ {
- pm8226_s1_corner: regulator-s1-corner {
- compatible = "qcom,stub-regulator";
- regulator-name = "8226_s1_corner";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <1>;
- regulator-max-microvolt = <7>;
- qcom,consumer-supplies = "vdd_dig", "";
- };
-};
-
/* QPNP controlled regulators: */
&spmi_bus {
-
qcom,pm8226@1 {
-
- pm8226_s1: regulator@1400 {
- status = "okay";
- regulator-name = "8226_s1";
- qcom,enable-time = <500>;
- qcom,system-load = <100000>;
- regulator-always-on;
- regulator-min-microvolt = <1150000>;
- regulator-max-microvolt = <1150000>;
- };
-
pm8226_s2: regulator@1700 {
status = "okay";
regulator-name = "8226_s2";
qcom,enable-time = <500>;
qcom,system-load = <100000>;
- regulator-always-on;
regulator-min-microvolt = <1050000>;
regulator-max-microvolt = <1150000>;
- };
-
- pm8226_s3: regulator@1a00 {
- status = "okay";
- regulator-name = "8226_s3";
- qcom,enable-time = <500>;
- qcom,system-load = <100000>;
regulator-always-on;
- regulator-min-microvolt = <1300000>;
+ };
+ };
+};
+
+/* RPM controlled regulators: */
+
+&rpm_bus {
+ rpm-regulator-smpa1 {
+ status = "okay";
+ pm8226_s1: regulator-s1 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1275000>;
+ status = "okay";
+ };
+ pm8226_s1_corner: regulator-s1-corner {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_s1_corner";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-corner;
+ qcom,consumer-supplies = "vdd_dig", "";
+ };
+ pm8226_s1_corner_ao: regulator-s1-corner-ao {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_s1_corner_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-corner;
+ };
+ };
+
+ rpm-regulator-smpa3 {
+ status = "okay";
+ pm8226_s3: regulator-s3 {
+ regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1300000>;
- };
-
- pm8226_s4: regulator@1d00 {
+ qcom,init-voltage = <1200000>;
status = "okay";
- regulator-name = "8226_s4";
- qcom,enable-time = <500>;
- qcom,system-load = <100000>;
- regulator-always-on;
+ };
+ };
+
+ rpm-regulator-smpa4 {
+ status = "okay";
+ pm8226_s4: regulator-s4 {
regulator-min-microvolt = <2100000>;
regulator-max-microvolt = <2100000>;
- };
-
- pm8226_s5: regulator@2000 {
+ qcom,init-voltage = <2100000>;
status = "okay";
- regulator-name = "8226_s5";
- qcom,enable-time = <500>;
+ };
+ };
+
+ rpm-regulator-smpa5 {
+ status = "okay";
+ pm8226_s5: regulator-s5 {
regulator-min-microvolt = <1150000>;
regulator-max-microvolt = <1150000>;
- };
-
- pm8226_l1: regulator@4000 {
+ qcom,init-voltage = <1150000>;
status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa1 {
+ status = "okay";
+ pm8226_l1: regulator-l1 {
regulator-name = "8226_l1";
- parent-supply = <&pm8226_s3>;
- qcom,enable-time = <200>;
regulator-min-microvolt = <1225000>;
regulator-max-microvolt = <1225000>;
- };
-
- pm8226_l2: regulator@4100 {
+ qcom,init-voltage = <1225000>;
status = "okay";
- regulator-name = "8226_l2";
- parent-supply = <&pm8226_s3>;
- regulator-always-on;
- qcom,enable-time = <200>;
- qcom,system-load = <10000>;
+ };
+ };
+
+ rpm-regulator-ldoa2 {
+ status = "okay";
+ pm8226_l2: regulator-l2 {
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
- };
-
- pm8226_l3: regulator@4200 {
+ qcom,init-voltage = <1200000>;
status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa3 {
+ status = "okay";
+ pm8226_l3: regulator-l3 {
regulator-name = "8226_l3";
- parent-supply = <&pm8226_s3>;
- qcom,system-load = <10000>;
- regulator-always-on;
- qcom,enable-time = <200>;
- regulator-min-microvolt = <1150000>;
- regulator-max-microvolt = <1150000>;
- };
-
- pm8226_l4: regulator@4300 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1275000>;
status = "okay";
+ };
+ pm8226_l3_ao: regulator-3-ao {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l3_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1275000>;
+ status = "okay";
+ };
+ pm8226_l3_so: regulator-l3-so {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8226_l3_so";
+ qcom,set = <2>;
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1275000>;
+ qcom,init-voltage = <750000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa4 {
+ status = "okay";
+ pm8226_l4: regulator-l4 {
regulator-name = "8226_l4";
- parent-supply = <&pm8226_s3>;
- qcom,enable-time = <200>;
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
- };
-
- pm8226_l5: regulator@4400 {
+ qcom,init-voltage = <1200000>;
status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa5 {
+ status = "okay";
+ pm8226_l5: regulator-l5 {
regulator-name = "8226_l5";
- parent-supply = <&pm8226_s3>;
- qcom,enable-time = <200>;
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
- };
-
- pm8226_l6: regulator@4500 {
+ qcom,init-voltage = <1200000>;
status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa6 {
+ status = "okay";
+ pm8226_l6: regulator-l6 {
regulator-name = "8226_l6";
- parent-supply = <&pm8226_s4>;
- qcom,system-load = <10000>;
- regulator-always-on;
- qcom,enable-time = <200>;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
- };
-
- pm8226_l7: regulator@4600 {
+ qcom,init-voltage = <1800000>;
status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa7 {
+ status = "okay";
+ pm8226_l7: regulator-l7 {
regulator-name = "8226_l7";
- parent-supply = <&pm8226_s4>;
- qcom,enable-time = <200>;
regulator-min-microvolt = <1850000>;
regulator-max-microvolt = <1850000>;
- };
-
- pm8226_l8: regulator@4700 {
+ qcom,init-voltage = <1850000>;
status = "okay";
- regulator-name = "8226_l8";
- parent-supply = <&pm8226_s4>;
- qcom,enable-time = <200>;
+ };
+ };
+
+ rpm-regulator-ldoa8 {
+ status = "okay";
+ pm8226_l8: regulator-l8 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
qcom,consumer-supplies = "vdd_sr2_pll", "";
};
+ };
- pm8226_l9: regulator@4800 {
- status = "okay";
+ rpm-regulator-ldoa9 {
+ status = "okay";
+ pm8226_l9: regulator-l9 {
regulator-name = "8226_l9";
- parent-supply = <&pm8226_s4>;
- qcom,enable-time = <200>;
regulator-min-microvolt = <2050000>;
regulator-max-microvolt = <2050000>;
- };
-
- pm8226_l10: regulator@4900 {
+ qcom,init-voltage = <2050000>;
status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa10 {
+ status = "okay";
+ pm8226_l10: regulator-l10 {
regulator-name = "8226_l10";
- parent-supply = <&pm8226_s4>;
- qcom,enable-time = <200>;
- qcom,system-load = <5000>;
- regulator-always-on;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
- };
-
- pm8226_l12: regulator@4b00 {
+ qcom,init-voltage = <1800000>;
status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa12 {
+ status = "okay";
+ pm8226_l12: regulator-l12 {
regulator-name = "8226_l12";
- qcom,enable-time = <200>;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
- };
-
- pm8226_l14: regulator@4d00 {
+ qcom,init-voltage = <1800000>;
status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa14 {
+ status = "okay";
+ pm8226_l14: regulator-l14 {
regulator-name = "8226_l14";
- qcom,enable-time = <200>;
regulator-min-microvolt = <2750000>;
regulator-max-microvolt = <2750000>;
- };
-
- pm8226_l15: regulator@4e00 {
+ qcom,init-voltage = <2750000>;
status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa15 {
+ status = "okay";
+ pm8226_l15: regulator-l15 {
regulator-name = "8226_l15";
- qcom,enable-time = <200>;
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
- };
-
- pm8226_l16: regulator@4f00 {
+ qcom,init-voltage = <2800000>;
status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa16 {
+ status = "okay";
+ pm8226_l16: regulator-l16 {
regulator-name = "8226_l16";
- qcom,enable-time = <200>;
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3300000>;
- };
-
- pm8226_l17: regulator@5000 {
+ qcom,init-voltage = <3300000>;
status = "okay";
- regulator-name = "8226_l17";
- qcom,enable-time = <200>;
+ };
+ };
+
+ rpm-regulator-ldoa17 {
+ status = "okay";
+ pm8226_l17: regulator-l17 {
regulator-min-microvolt = <2950000>;
regulator-max-microvolt = <2950000>;
- };
-
- pm8226_l18: regulator@5100 {
+ qcom,init-voltage = <2950000>;
status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa18 {
+ status = "okay";
+ pm8226_l18: regulator-l18 {
regulator-name = "8226_l18";
- qcom,enable-time = <200>;
regulator-min-microvolt = <2950000>;
regulator-max-microvolt = <2950000>;
- };
-
- pm8226_l19: regulator@5200 {
+ qcom,init-voltage = <2950000>;
status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa19 {
+ status = "okay";
+ pm8226_l19: regulator-l19 {
regulator-name = "8226_l19";
- qcom,enable-time = <200>;
regulator-min-microvolt = <2850000>;
regulator-max-microvolt = <2850000>;
- };
-
- pm8226_l20: regulator@5300 {
+ qcom,init-voltage = <2850000>;
status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa20 {
+ status = "okay";
+ pm8226_l20: regulator-l20 {
regulator-name = "8226_l20";
- qcom,enable-time = <200>;
regulator-min-microvolt = <3075000>;
regulator-max-microvolt = <3075000>;
- };
-
- pm8226_l21: regulator@5400 {
+ qcom,init-voltage = <3075000>;
status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa21 {
+ status = "okay";
+ pm8226_l21: regulator-l21 {
regulator-name = "8226_l21";
- qcom,enable-time = <200>;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <2950000>;
- };
-
- pm8226_l22: regulator@5500 {
+ qcom,init-voltage = <2950000>;
status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa22 {
+ status = "okay";
+ pm8226_l22: regulator-l22 {
regulator-name = "8226_l22";
- qcom,enable-time = <200>;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <2950000>;
- };
-
- pm8226_l23: regulator@5600 {
+ qcom,init-voltage = <2950000>;
status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa23 {
+ status = "okay";
+ pm8226_l23: regulator-l23 {
regulator-name = "8226_l23";
- qcom,enable-time = <200>;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <2950000>;
- };
-
- pm8226_l24: regulator@5700 {
+ qcom,init-voltage = <2950000>;
status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa24 {
+ status = "okay";
+ pm8226_l24: regulator-l24 {
regulator-name = "8226_l24";
- parent-supply = <&pm8226_s3>;
- qcom,enable-time = <200>;
regulator-min-microvolt = <1300000>;
regulator-max-microvolt = <1300000>;
- };
-
- pm8226_l26: regulator@5900 {
+ qcom,init-voltage = <1300000>;
status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa26 {
+ status = "okay";
+ pm8226_l26: regulator-l26 {
regulator-name = "8226_l26";
- parent-supply = <&pm8226_s3>;
- qcom,enable-time = <200>;
regulator-min-microvolt = <1225000>;
regulator-max-microvolt = <1225000>;
- };
-
- pm8226_l27: regulator@5a00 {
+ qcom,init-voltage = <1225000>;
status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa27 {
+ status = "okay";
+ pm8226_l27: regulator-l27 {
regulator-name = "8226_l27";
- parent-supply = <&pm8226_s4>;
- qcom,enable-time = <200>;
regulator-min-microvolt = <2050000>;
regulator-max-microvolt = <2050000>;
- };
-
- pm8226_l28: regulator@5b00 {
+ qcom,init-voltage = <2050000>;
status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa28 {
+ status = "okay";
+ pm8226_l28: regulator-l28 {
regulator-name = "8226_l28";
- qcom,enable-time = <200>;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <2950000>;
- };
-
- pm8226_lvs1: regulator@8000 {
+ qcom,init-voltage = <2950000>;
status = "okay";
- regulator-name = "8226_lvs1";
- parent-supply = <&pm8226_l6>;
- qcom,enable-time = <200>;
+ };
+ };
+
+ rpm-regulator-vsa1 {
+ status = "okay";
+ pm8226_lvs1: regulator-lvs1 {
+ status = "okay";
};
};
};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 2ceaaaa..223675d 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -504,7 +504,7 @@
reg = <0xfdd00000 0x2000>,
<0xfdd02000 0x2000>,
<0xfe039000 0x400>,
- <0xfec00000 0x180000>;
+ <0xfec00000 0x20000>;
reg-names = "ocmem_ctrl_physical", "dm_ctrl_physical", "br_ctrl_physical", "ocmem_physical";
interrupts = <0 76 0 0 77 0>;
interrupt-names = "ocmem_irq", "dm_irq";
@@ -513,12 +513,12 @@
qcom,resource-type = <0x706d636f>;
#address-cells = <1>;
#size-cells = <1>;
- ranges = <0x0 0xfec00000 0x180000>;
+ ranges = <0x0 0xfec00000 0x20000>;
partition@0 {
- reg = <0x0 0x100000>;
+ reg = <0x0 0x20000>;
qcom,ocmem-part-name = "graphics";
- qcom,ocmem-part-min = <0x80000>;
+ qcom,ocmem-part-min = <0x20000>;
};
};
@@ -617,7 +617,7 @@
gpios = <&msmgpio 3 0>, /* CLK */
<&msmgpio 1 0>, /* MISO */
<&msmgpio 0 0>; /* MOSI */
- cs-gpios = <&msmgpio 2 0>;
+ cs-gpios = <&msmgpio 22 0>;
qcom,infinite-mode = <0>;
qcom,use-bam;
@@ -637,6 +637,17 @@
qcom,memory-reservation-type = "EBI1";
qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
};
+
+ qcom,msm-rng@f9bff000 {
+ compatible = "qcom,msm-rng";
+ reg = <0xf9bff000 0x200>;
+ qcom,msm-rng-iface-clk;
+ };
+
+ qcom,tz-log@fc5b82c {
+ compatible = "qcom,tz-log";
+ reg = <0x0fc5b82c 0x1000>;
+ };
};
&gdsc_venus {
@@ -663,6 +674,7 @@
status = "ok";
};
+/include/ "msm-pm8226-rpm-regulator.dtsi"
/include/ "msm-pm8226.dtsi"
/include/ "msm8226-regulator.dtsi"
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 2dff4c7..fe0ebf9 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -437,6 +437,19 @@
vdd_cx-supply = <&pm8110_s1_corner>;
qcom,firmware-name = "adsp";
};
+
+ tsens: tsens@fc4a8000 {
+ compatible = "qcom,msm-tsens";
+ reg = <0xfc4a8000 0x2000>,
+ <0xfc4b8000 0x1000>;
+ reg-names = "tsens_physical", "tsens_eeprom_physical";
+ interrupts = <0 184 0>;
+ qcom,sensors = <2>;
+ qcom,slope = <2901 2846>;
+ qcom,calib-mode = "fuse_map2";
+ qcom,calibration-less-mode;
+ };
+
};
&gdsc_vfe {
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-cdp-mtp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-cdp-mtp.dtsi
index fb2917c..24438f0 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-cdp-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-cdp-mtp.dtsi
@@ -22,7 +22,7 @@
qcom,camera@6e {
compatible = "qcom,s5k3l1yx";
- reg = <0x6e 0x0>;
+ reg = <0x6e>;
qcom,slave-id = <0x6e 0x0 0x3121>;
qcom,csiphy-sd-index = <0>;
qcom,csid-sd-index = <0>;
@@ -63,7 +63,7 @@
qcom,camera@6c {
compatible = "qcom,ov2720";
- reg = <0x6c 0x0>;
+ reg = <0x6c>;
qcom,slave-id = <0x6c 0x300A 0x2720>;
qcom,csiphy-sd-index = <2>;
qcom,csid-sd-index = <0>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
index 4fe4220..c9d1abc 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
@@ -15,7 +15,7 @@
actuator0: qcom,actuator@18 {
cell-index = <0>;
- reg = <0x18 0x0>;
+ reg = <0x18>;
compatible = "qcom,actuator";
qcom,cci-master = <0>;
};
@@ -99,7 +99,7 @@
qcom,camera@90 {
compatible = "qcom,mt9m114";
- reg = <0x90 0x0>;
+ reg = <0x90>;
qcom,slave-id = <0x90 0x0 0x2481>;
qcom,csiphy-sd-index = <1>;
qcom,csid-sd-index = <0>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
index b313795..f9b89e1 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
@@ -16,14 +16,14 @@
actuator0: qcom,actuator@18 {
cell-index = <0>;
- reg = <0x18 0x0>;
+ reg = <0x18>;
compatible = "qcom,actuator";
qcom,cci-master = <0>;
};
qcom,camera@6e {
compatible = "qcom,s5k3l1yx";
- reg = <0x6e 0x0>;
+ reg = <0x6e>;
qcom,slave-id = <0x6e 0x0 0x3121>;
qcom,csiphy-sd-index = <0>;
qcom,csid-sd-index = <0>;
@@ -60,7 +60,7 @@
qcom,camera@6c {
compatible = "qcom,ov2720";
- reg = <0x6c 0x0>;
+ reg = <0x6c>;
qcom,slave-id = <0x6c 0x300A 0x2720>;
qcom,csiphy-sd-index = <2>;
qcom,csid-sd-index = <0>;
@@ -95,7 +95,7 @@
qcom,camera@90 {
compatible = "qcom,mt9m114";
- reg = <0x90 0x0>;
+ reg = <0x90>;
qcom,slave-id = <0x90 0x0 0x2481>;
qcom,csiphy-sd-index = <1>;
qcom,csid-sd-index = <0>;
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index ebb3912..95cafdb 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -179,8 +179,7 @@
compatible = "qcom,cci";
reg = <0xfda0C000 0x1000>;
#address-cells = <1>;
- #size-cells = <1>;
- ranges;
+ #size-cells = <0>;
reg-names = "cci";
interrupts = <0 50 0>;
interrupt-names = "cci";
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index ad26061..2b1cbb5 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -314,6 +314,17 @@
};
&sdhc_2 {
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0
+ 2 &msmgpio 62 0x3>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&msmgpio 62 0x1>;
+
vdd-supply = <&pm8941_l21>;
vdd-io-supply = <&pm8941_l13>;
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index dbb8958..d22c746 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -311,6 +311,17 @@
};
&sdhc_2 {
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0
+ 2 &msmgpio 62 0x3>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&msmgpio 62 0x1>;
+
vdd-supply = <&pm8941_l21>;
vdd-io-supply = <&pm8941_l13>;
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 4dd92b98..985b307 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -351,11 +351,18 @@
hub_int-supply = <&pm8941_l10>;
hub_vbus-supply = <&ext_5v>;
- hsic@f9a00000 {
+ hsic_host: hsic@f9a00000 {
compatible = "qcom,hsic-host";
reg = <0xf9a00000 0x400>;
- interrupts = <0 136 0>, <0 148 0>;
- interrupt-names = "core_irq", "async_irq";
+ #address-cells = <0>;
+ interrupt-parent = <&hsic_host>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 136 0
+ 1 &intc 0 148 0
+ 2 &msmgpio 144 0x8>;
+ interrupt-names = "core_irq", "async_irq", "wakeup";
HSIC_VDDCX-supply = <&pm8841_s2>;
HSIC_GDSC-supply = <&gdsc_usb_hsic>;
hsic,strobe-gpio = <&msmgpio 144 0x00>;
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index d3d53dd..380ec20 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -282,6 +282,17 @@
};
&sdhc_2 {
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0
+ 2 &msmgpio 62 0x3>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&msmgpio 62 0x1>;
+
vdd-supply = <&pm8941_l21>;
vdd-io-supply = <&pm8941_l13>;
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index fda8752..91e0c29 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -340,7 +340,8 @@
qcom,ipc-bit-offset = <1>;
qcom,gic-parent = <&intc>;
- qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
+ qcom,gic-map = <47 165>, /* usb30_hs_phy_irq */
+ <50 172>, /* usb1_hs_async_wakeup_irq */
<53 104>, /* mdss_irq */
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
<0xff 57>, /* mss_to_apps_irq(0) */
@@ -413,7 +414,8 @@
<37 86>,
<38 92>,
<39 93>,
- <40 95>;
+ <40 95>,
+ <41 144>;
};
qcom,pm-8x60@fe805664 {
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index f0eed3f..fadf5da 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -337,7 +337,8 @@
qcom,ipc-bit-offset = <1>;
qcom,gic-parent = <&intc>;
- qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
+ qcom,gic-map = <47 165>, /* usb30_hs_phy_irq */
+ <50 172>, /* usb1_hs_async_wakeup_irq */
<53 104>, /* mdss_irq */
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
<0xff 57>, /* mss_to_apps_irq(0) */
@@ -410,7 +411,8 @@
<37 86>,
<38 92>,
<39 93>,
- <40 95>;
+ <40 95>,
+ <41 144>;
};
qcom,pm-8x60@fe805664 {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 99886c7..3ebdbb6 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -84,9 +84,10 @@
clock-frequency = <19200000>;
};
- qcom,mpm-counter@fc4a3000 {
- compatible = "qcom,mpm-counter";
+ qcom,mpm2-sleep-counter@fc4a3000 {
+ compatible = "qcom,mpm2-sleep-counter";
reg = <0xfc4a3000 0x1000>;
+ clock-frequency = <32768>;
};
msm_vidc: qcom,vidc@fdc00000 {
@@ -1382,6 +1383,17 @@
reg = <0xfa00000 0x200000>;
status = "disable";
};
+
+ cpu-pmu {
+ compatible = "qcom,krait-pmu";
+ qcom,irq-is-percpu;
+ interrupts = <1 7 0xf00>;
+ };
+
+ l2-pmu {
+ compatible = "qcom,l2-pmu";
+ interrupts = <0 1 0>;
+ };
};
&gdsc_venus {
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index e1501ac..78786f6 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -52,6 +52,12 @@
qcom,direct-connect-irqs = <8>;
};
+ qcom,mpm2-sleep-counter@fc4a3000 {
+ compatible = "qcom,mpm2-sleep-counter";
+ reg = <0xfc4a3000 0x1000>;
+ clock-frequency = <32768>;
+ };
+
timer: msm-qtimer@f9021000 {
compatible = "arm,armv7-timer";
reg = <0xF9021000 0x1000>;
@@ -731,6 +737,17 @@
status = "disable";
};
+ cpu-pmu {
+ compatible = "arm,cortex-a5-pmu";
+ qcom,irq-is-percpu;
+ interrupts = <1 7 0x00>;
+ };
+
+ l2-pmu {
+ compatible = "qcom,l2-pmu";
+ interrupts = <0 1 0>;
+ };
+
};
/include/ "msm-pm8019-rpm-regulator.dtsi"
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 9e38eca..b163a5d 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -58,8 +58,6 @@
CONFIG_MSM_PIL_PRONTO=y
CONFIG_MSM_PIL_MSS_QDSP6V5=y
CONFIG_MSM_PIL_VENUS=y
-CONFIG_WCNSS_CORE=y
-CONFIG_WCNSS_CORE_PRONTO=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_DLOAD_MODE=y
@@ -125,6 +123,7 @@
CONFIG_DUMMY=y
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
+CONFIG_KS8851=y
CONFIG_WCNSS_CORE=y
CONFIG_WCNSS_CORE_PRONTO=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
@@ -141,6 +140,7 @@
CONFIG_SERIAL_MSM_HSL_CONSOLE=y
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
CONFIG_SPMI=y
CONFIG_SPMI_MSM_PMIC_ARB=y
CONFIG_MSM_QPNP_INT=y
@@ -159,7 +159,6 @@
CONFIG_HWMON=y
CONFIG_POWER_SUPPLY=y
CONFIG_QPNP_CHARGER=y
-# CONFIG_HWMON is not set
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
CONFIG_SENSORS_QPNP_ADC_CURRENT=y
CONFIG_REGULATOR=y
@@ -250,7 +249,6 @@
CONFIG_VIDEO_DEV=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
CONFIG_VIDEOBUF2_MSM_MEM=y
-CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_OCMEM=y
CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
CONFIG_MSM_OCMEM_DEBUG=y
@@ -268,3 +266,8 @@
CONFIG_CORESIGHT_STM=y
CONFIG_CORESIGHT_EVENT=m
CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+CONFIG_PM_AUTOSLEEP=y
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_MSM_TZ_LOG=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 89f9d4a..a8ea31d 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -531,3 +531,7 @@
CONFIG_CRC_CCITT=y
CONFIG_SYNC=y
CONFIG_SW_SYNC=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+CONFIG_PM_AUTOSLEEP=y
+# CONFIG_PM_WAKELOCKS_GC is not set
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 5b9c590..9f10bc4 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -549,3 +549,7 @@
CONFIG_CRC_CCITT=y
CONFIG_SYNC=y
CONFIG_SW_SYNC=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+CONFIG_PM_AUTOSLEEP=y
+# CONFIG_PM_WAKELOCKS_GC is not set
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index c74262c..ea10007 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -291,6 +291,7 @@
CONFIG_SPMI=y
CONFIG_SPMI_MSM_PMIC_ARB=y
CONFIG_MSM_QPNP_INT=y
+CONFIG_QPNP_REVID=y
CONFIG_SLIMBUS_MSM_NGD=y
CONFIG_DEBUG_GPIO=y
CONFIG_GPIO_SYSFS=y
@@ -422,6 +423,7 @@
CONFIG_QPNP_PWM=y
CONFIG_QPNP_POWER_ON=y
CONFIG_QPNP_CLKDIV=y
+CONFIG_QPNP_COINCELL=y
CONFIG_MSM_IOMMU=y
CONFIG_MOBICORE_SUPPORT=m
CONFIG_MOBICORE_API=m
@@ -468,3 +470,7 @@
CONFIG_CRYPTO_DEV_QCEDEV=y
CONFIG_CRC_CCITT=y
CONFIG_MSM_EVENT_TIMER=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+CONFIG_PM_AUTOSLEEP=y
+# CONFIG_PM_WAKELOCKS_GC is not set
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 48ea1a4..077c7a6 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -296,6 +296,7 @@
CONFIG_SPMI=y
CONFIG_SPMI_MSM_PMIC_ARB=y
CONFIG_MSM_QPNP_INT=y
+CONFIG_QPNP_REVID=y
CONFIG_SLIMBUS_MSM_NGD=y
CONFIG_DEBUG_GPIO=y
CONFIG_GPIO_SYSFS=y
@@ -430,6 +431,7 @@
CONFIG_QPNP_PWM=y
CONFIG_QPNP_POWER_ON=y
CONFIG_QPNP_CLKDIV=y
+CONFIG_QPNP_COINCELL=y
CONFIG_MSM_IOMMU=y
CONFIG_MSM_IOMMU_PMON=y
CONFIG_MOBICORE_SUPPORT=m
@@ -493,3 +495,7 @@
CONFIG_CRYPTO_DEV_QCEDEV=y
CONFIG_CRC_CCITT=y
CONFIG_MSM_EVENT_TIMER=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+CONFIG_PM_AUTOSLEEP=y
+# CONFIG_PM_WAKELOCKS_GC is not set
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index 1fe528a..f525eee 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -323,3 +323,7 @@
CONFIG_SCSI_SCAN_ASYNC=y
CONFIG_MSM_RTB=y
CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+CONFIG_PM_AUTOSLEEP=y
+# CONFIG_PM_WAKELOCKS_GC is not set
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index aa18209..f3a7b5c 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -324,3 +324,7 @@
CONFIG_SCSI_SCAN_ASYNC=y
CONFIG_MSM_RTB=y
CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+CONFIG_PM_AUTOSLEEP=y
+# CONFIG_PM_WAKELOCKS_GC is not set
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index d1a3e61..e1fc42f 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -52,6 +52,10 @@
void (*disable_irq)(int irq);
};
+extern int multicore_request_irq(int irq, irq_handler_t *handle_irq);
+extern void multicore_free_irq(int irq);
+extern struct arm_pmu_platdata multicore_data;
+
#ifdef CONFIG_CPU_HAS_PMU
/**
@@ -151,9 +155,6 @@
struct hw_perf_event *hwc,
int idx);
-extern void enable_irq_callback(void *);
-extern void disable_irq_callback(void *);
-
#endif /* CONFIG_HW_PERF_EVENTS */
#endif /* __ARM_PMU_H__ */
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 5311d74..cef66ec 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -21,6 +21,7 @@
#include <linux/spinlock.h>
#include <linux/uaccess.h>
#include <linux/irq.h>
+#include <linux/of.h>
#include <asm/cputype.h>
#include <asm/irq.h>
@@ -51,6 +52,8 @@
/* Set at runtime when we know what CPU type we are. */
static struct arm_pmu *cpu_pmu;
+static int per_cpu_irq;
+
enum arm_perf_pmu_ids
armpmu_get_pmu_id(void)
{
@@ -381,6 +384,58 @@
return plat->handle_irq(irq, dev, armpmu->handle_irq);
}
+static DEFINE_PER_CPU(u32, pmu_irq_cookie);
+
+void enable_irq_callback(void *info)
+{
+ int irq = *(unsigned int *)info;
+ enable_percpu_irq(irq, IRQ_TYPE_EDGE_RISING);
+}
+
+void disable_irq_callback(void *info)
+{
+ int irq = *(unsigned int *)info;
+ disable_percpu_irq(irq);
+}
+
+int
+multicore_request_irq(int irq, irq_handler_t *handle_irq)
+{
+ int err = 0;
+ int cpu;
+
+ err = request_percpu_irq(irq, *handle_irq, "l1-armpmu",
+ &pmu_irq_cookie);
+
+ if (!err) {
+ for_each_cpu(cpu, cpu_online_mask) {
+ smp_call_function_single(cpu,
+ enable_irq_callback, &irq, 1);
+ }
+ }
+
+ return err;
+}
+
+void
+multicore_free_irq(int irq)
+{
+ int cpu;
+
+ if (irq >= 0) {
+ for_each_cpu(cpu, cpu_online_mask) {
+ smp_call_function_single(cpu,
+ disable_irq_callback, &irq, 1);
+ }
+ free_percpu_irq(irq, &pmu_irq_cookie);
+ }
+}
+
+struct arm_pmu_platdata multicore_data = {
+ .request_pmu_irq = multicore_request_irq,
+ .free_pmu_irq = multicore_free_irq,
+};
+
int
armpmu_generic_request_irq(int irq, irq_handler_t *handle_irq)
{
@@ -689,11 +744,12 @@
{.compatible = "arm,cortex-a8-pmu"},
{.compatible = "arm,arm1136-pmu"},
{.compatible = "arm,arm1176-pmu"},
+ {.compatible = "qcom,krait-pmu"},
{},
};
static struct platform_device_id armpmu_plat_device_ids[] = {
- {.name = "cpu-arm-pmu"},
+ {.name = "cpu-pmu"},
{},
};
@@ -703,12 +759,16 @@
return -ENODEV;
cpu_pmu->plat_device = pdev;
+
+ if (per_cpu_irq == 1)
+ cpu_pmu->plat_device->dev.platform_data = &multicore_data;
+
return 0;
}
static struct platform_driver armpmu_driver = {
.driver = {
- .name = "cpu-arm-pmu",
+ .name = "cpu-pmu",
.of_match_table = armpmu_of_device_ids,
},
.probe = armpmu_device_probe,
@@ -756,18 +816,6 @@
return 0;
}
-void enable_irq_callback(void *info)
-{
- int irq = *(unsigned int *)info;
- enable_percpu_irq(irq, IRQ_TYPE_EDGE_RISING);
-}
-
-void disable_irq_callback(void *info)
-{
- int irq = *(unsigned int *)info;
- disable_percpu_irq(irq);
-}
-
/*
* PMU hardware loses all context when a CPU goes offline.
* When a CPU is hotplugged back in, since some hardware registers are
@@ -881,6 +929,24 @@
.notifier_call = perf_cpu_pm_notifier,
};
+#ifdef CONFIG_OF
+static inline int get_dt_irq_prop(void)
+{
+ struct device_node *np = NULL;
+ int err = -1;
+
+ np = of_find_matching_node(NULL, armpmu_of_device_ids);
+ if (np)
+ err = of_property_read_bool(np, "qcom,irq-is-percpu");
+ else
+ pr_err("Perf: can't find DT node.\n");
+
+ return err;
+}
+#else
+static inline int get_dt_irq_prop(void) {return 0; }
+#endif
+
/*
* CPU PMU identification and registration.
*/
@@ -956,6 +1022,8 @@
register_cpu_notifier(&pmu_cpu_notifier);
armpmu_register(cpu_pmu, "cpu", PERF_TYPE_RAW);
cpu_pm_register_notifier(&perf_cpu_pm_notifier_block);
+ per_cpu_irq = get_dt_irq_prop();
+
} else {
pr_info("no hardware support available\n");
}
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index f39046c..ce557b1 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -390,16 +390,17 @@
select MSM_GPIOMUX
select MSM_NATIVE_RESTART
select MSM_RESTART_V2
- select MEMORY_HOLE_CARVEOUT
- select DONT_MAP_HOLE_AFTER_MEMBANK
- select QMI_ENCDEC
select MSM_QDSP6_APRV2
select MSM_QDSP6V2_CODECS
select MSM_AUDIO_QDSP6V2 if SND_SOC
+ select QMI_ENCDEC
select MSM_RPM_SMD
select MSM_SPM_V2
select MSM_L2_SPM
select MSM_PM8X60 if PM
+ select MEMORY_HOLE_CARVEOUT
+ select DONT_MAP_HOLE_AFTER_MEMBANK0
+ select MSM_BUS_SCALING
select CPU_FREQ_MSM
select CPU_FREQ
select CPU_FREQ_GOV_USERSPACE
@@ -407,6 +408,8 @@
select MSM_PIL
select MSM_RUN_QUEUE_STATS
select ARM_HAS_SG_CHAIN
+ select REGULATOR
+ select MSM_RPM_REGULATOR_SMD
config ARCH_MSM8226
bool "MSM8226"
@@ -433,6 +436,12 @@
select MEMORY_HOLE_CARVEOUT
select DONT_MAP_HOLE_AFTER_MEMBANK0
select MSM_BUS_SCALING
+ select CPU_FREQ_MSM
+ select CPU_FREQ
+ select CPU_FREQ_GOV_USERSPACE
+ select CPU_FREQ_GOV_ONDEMAND
+ select MSM_PIL
+ select MSM_RUN_QUEUE_STATS
select ARM_HAS_SG_CHAIN
select REGULATOR
select MSM_RPM_REGULATOR_SMD
@@ -2850,4 +2859,12 @@
depends on SERIAL_MSM_HS
help
Select if BLSP based UART Core v.14 or higher is present.
+
+config MSM_BOOT_STATS
+ bool "Use MSM boot stats reporting"
+ help
+ Use this to report msm boot stats such as bootloader throughput,
+ display init, total boot time.
+ This figures are reported in mpm sleep clock cycles and have a
+ resolution of 31 bits as 1 bit is used as an overflow check.
endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index cb5e712..fb7e4e3 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -29,15 +29,17 @@
obj-$(CONFIG_DEBUG_FS) += acpuclock-krait-debug.o
endif
obj-$(CONFIG_ARCH_MSM7X27) += acpuclock-7627.o acpuclock-8625q.o clock-pll.o
-obj-$(CONFIG_ARCH_MSM_SCORPION) += pmu.o
obj-$(CONFIG_ARCH_MSM_SCORPIONMP) += perf_event_msm_l2.o
-obj-$(CONFIG_ARCH_MSM_KRAIT) += msm-krait-l2-accessors.o pmu.o perf_event_msm_krait_l2.o
+ifndef CONFIG_OF
+obj-$(CONFIG_HW_PERF_EVENTS) += pmu.o
+endif
+obj-$(CONFIG_ARCH_MSM_KRAIT) += msm-krait-l2-accessors.o perf_event_msm_krait_l2.o
obj-$(CONFIG_ARCH_MSM_KRAIT) += krait-scm.o
ifdef CONFIG_HW_PERF_EVENTS
-obj-$(CONFIG_ARCH_MSM7X27A) += pmu.o perf_event_msm_pl310.o
-obj-$(CONFIG_ARCH_MSM9625) += pmu.o perf_event_msm_pl310.o
-obj-$(CONFIG_ARCH_MSM8625) += pmu.o perf_event_msm_pl310.o
-obj-$(CONFIG_ARCH_MSM9615) += pmu.o perf_event_msm_pl310.o
+obj-$(CONFIG_ARCH_MSM7X27A) += perf_event_msm_pl310.o
+obj-$(CONFIG_ARCH_MSM9625) += perf_event_msm_pl310.o
+obj-$(CONFIG_ARCH_MSM8625) += perf_event_msm_pl310.o
+obj-$(CONFIG_ARCH_MSM9615) += perf_event_msm_pl310.o
obj-$(CONFIG_DEBUG_FS) += perf_debug.o
endif
@@ -193,6 +195,7 @@
obj-$(CONFIG_ARCH_MSM8X60) += clock-rpm.o
obj-$(CONFIG_ARCH_MSM8X60) += saw-regulator.o
obj-$(CONFIG_ARCH_MSM8X60) += footswitch-8x60.o
+obj-$(CONFIG_MSM_BOOT_STATS) += boot_stats.o
ifdef CONFIG_MSM_RPM_REGULATOR
obj-y += rpm-regulator.o
@@ -300,7 +303,7 @@
obj-$(CONFIG_ARCH_MSM8930) += acpuclock-8930.o acpuclock-8627.o acpuclock-8930aa.o acpuclock-8930ab.o
obj-$(CONFIG_ARCH_MPQ8092) += board-8092.o board-8092-gpiomux.o
obj-$(CONFIG_ARCH_MSM8226) += board-8226.o board-8226-gpiomux.o
-obj-$(CONFIG_ARCH_MSM8226) += clock-local2.o clock-pll.o clock-8226.o clock-rpm.o clock-voter.o clock-mdss-8974.o
+obj-$(CONFIG_ARCH_MSM8226) += clock-local2.o clock-pll.o clock-8226.o clock-rpm.o clock-voter.o clock-mdss-8226.o
obj-$(CONFIG_ARCH_MSM8226) += acpuclock-8226.o acpuclock-cortex.o
obj-$(CONFIG_ARCH_MSM8610) += board-8610.o board-8610-gpiomux.o
obj-$(CONFIG_ARCH_MSM8610) += clock-local2.o clock-pll.o clock-8610.o clock-rpm.o clock-voter.o
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index efd0045..83c14a8 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -308,6 +308,168 @@
{ 0, { 0 } }
};
+static struct acpu_level acpu_freq_tbl_2g_pvs1[] __initdata = {
+ { 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 400000 },
+ { 0, { 345600, HFPLL, 2, 36 }, L2(3), 810000, 3200000 },
+ { 1, { 422400, HFPLL, 2, 44 }, L2(3), 820000, 3200000 },
+ { 0, { 499200, HFPLL, 2, 52 }, L2(6), 830000, 3200000 },
+ { 1, { 576000, HFPLL, 1, 30 }, L2(6), 840000, 3200000 },
+ { 1, { 652800, HFPLL, 1, 34 }, L2(7), 850000, 3200000 },
+ { 1, { 729600, HFPLL, 1, 38 }, L2(7), 860000, 3200000 },
+ { 0, { 806400, HFPLL, 1, 42 }, L2(10), 875000, 3200000 },
+ { 1, { 883200, HFPLL, 1, 46 }, L2(10), 885000, 3200000 },
+ { 0, { 960000, HFPLL, 1, 50 }, L2(10), 895000, 3200000 },
+ { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 910000, 3200000 },
+ { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 920000, 3200000 },
+ { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 930000, 3200000 },
+ { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 945000, 3200000 },
+ { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 960000, 3200000 },
+ { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 975000, 3200000 },
+ { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 990000, 3200000 },
+ { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 1005000, 3200000 },
+ { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 1020000, 3200000 },
+ { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 1030000, 3200000 },
+ { 0, { 1804800, HFPLL, 1, 94 }, L2(19), 1045000, 3200000 },
+ { 0, { 1881600, HFPLL, 1, 98 }, L2(19), 1060000, 3200000 },
+ { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1075000, 3200000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_2g_pvs2[] __initdata = {
+ { 1, { 300000, PLL_0, 0, 0 }, L2(0), 785000, 400000 },
+ { 0, { 345600, HFPLL, 2, 36 }, L2(3), 795000, 3200000 },
+ { 1, { 422400, HFPLL, 2, 44 }, L2(3), 805000, 3200000 },
+ { 0, { 499200, HFPLL, 2, 52 }, L2(6), 815000, 3200000 },
+ { 1, { 576000, HFPLL, 1, 30 }, L2(6), 825000, 3200000 },
+ { 1, { 652800, HFPLL, 1, 34 }, L2(7), 835000, 3200000 },
+ { 1, { 729600, HFPLL, 1, 38 }, L2(7), 845000, 3200000 },
+ { 0, { 806400, HFPLL, 1, 42 }, L2(10), 855000, 3200000 },
+ { 1, { 883200, HFPLL, 1, 46 }, L2(10), 865000, 3200000 },
+ { 0, { 960000, HFPLL, 1, 50 }, L2(10), 875000, 3200000 },
+ { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 890000, 3200000 },
+ { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 900000, 3200000 },
+ { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 910000, 3200000 },
+ { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 925000, 3200000 },
+ { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 940000, 3200000 },
+ { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 955000, 3200000 },
+ { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 970000, 3200000 },
+ { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 980000, 3200000 },
+ { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 995000, 3200000 },
+ { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 1005000, 3200000 },
+ { 0, { 1804800, HFPLL, 1, 94 }, L2(19), 1020000, 3200000 },
+ { 0, { 1881600, HFPLL, 1, 98 }, L2(19), 1035000, 3200000 },
+ { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1050000, 3200000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_2g_pvs3[] __initdata = {
+ { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 400000 },
+ { 0, { 345600, HFPLL, 2, 36 }, L2(3), 780000, 3200000 },
+ { 1, { 422400, HFPLL, 2, 44 }, L2(3), 790000, 3200000 },
+ { 0, { 499200, HFPLL, 2, 52 }, L2(6), 800000, 3200000 },
+ { 1, { 576000, HFPLL, 1, 30 }, L2(6), 810000, 3200000 },
+ { 1, { 652800, HFPLL, 1, 34 }, L2(7), 820000, 3200000 },
+ { 1, { 729600, HFPLL, 1, 38 }, L2(7), 830000, 3200000 },
+ { 0, { 806400, HFPLL, 1, 42 }, L2(10), 840000, 3200000 },
+ { 1, { 883200, HFPLL, 1, 46 }, L2(10), 850000, 3200000 },
+ { 0, { 960000, HFPLL, 1, 50 }, L2(10), 860000, 3200000 },
+ { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 875000, 3200000 },
+ { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 885000, 3200000 },
+ { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 895000, 3200000 },
+ { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 910000, 3200000 },
+ { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 925000, 3200000 },
+ { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 935000, 3200000 },
+ { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 950000, 3200000 },
+ { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 960000, 3200000 },
+ { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 970000, 3200000 },
+ { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 985000, 3200000 },
+ { 0, { 1804800, HFPLL, 1, 94 }, L2(19), 995000, 3200000 },
+ { 0, { 1881600, HFPLL, 1, 98 }, L2(19), 1010000, 3200000 },
+ { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1025000, 3200000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_2g_pvs4[] __initdata = {
+ { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 400000 },
+ { 0, { 345600, HFPLL, 2, 36 }, L2(3), 775000, 3200000 },
+ { 1, { 422400, HFPLL, 2, 44 }, L2(3), 780000, 3200000 },
+ { 0, { 499200, HFPLL, 2, 52 }, L2(6), 790000, 3200000 },
+ { 1, { 576000, HFPLL, 1, 30 }, L2(6), 800000, 3200000 },
+ { 1, { 652800, HFPLL, 1, 34 }, L2(7), 810000, 3200000 },
+ { 1, { 729600, HFPLL, 1, 38 }, L2(7), 820000, 3200000 },
+ { 0, { 806400, HFPLL, 1, 42 }, L2(10), 830000, 3200000 },
+ { 1, { 883200, HFPLL, 1, 46 }, L2(10), 840000, 3200000 },
+ { 0, { 960000, HFPLL, 1, 50 }, L2(10), 850000, 3200000 },
+ { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 860000, 3200000 },
+ { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 870000, 3200000 },
+ { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 880000, 3200000 },
+ { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 895000, 3200000 },
+ { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 910000, 3200000 },
+ { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 920000, 3200000 },
+ { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 930000, 3200000 },
+ { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 940000, 3200000 },
+ { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 950000, 3200000 },
+ { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 960000, 3200000 },
+ { 0, { 1804800, HFPLL, 1, 94 }, L2(19), 975000, 3200000 },
+ { 0, { 1881600, HFPLL, 1, 98 }, L2(19), 985000, 3200000 },
+ { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1000000, 3200000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_2g_pvs5[] __initdata = {
+ { 1, { 300000, PLL_0, 0, 0 }, L2(0), 750000, 400000 },
+ { 0, { 345600, HFPLL, 2, 36 }, L2(3), 760000, 3200000 },
+ { 1, { 422400, HFPLL, 2, 44 }, L2(3), 770000, 3200000 },
+ { 0, { 499200, HFPLL, 2, 52 }, L2(6), 780000, 3200000 },
+ { 1, { 576000, HFPLL, 1, 30 }, L2(6), 790000, 3200000 },
+ { 1, { 652800, HFPLL, 1, 34 }, L2(7), 800000, 3200000 },
+ { 1, { 729600, HFPLL, 1, 38 }, L2(7), 810000, 3200000 },
+ { 0, { 806400, HFPLL, 1, 42 }, L2(10), 820000, 3200000 },
+ { 1, { 883200, HFPLL, 1, 46 }, L2(10), 830000, 3200000 },
+ { 0, { 960000, HFPLL, 1, 50 }, L2(10), 840000, 3200000 },
+ { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 850000, 3200000 },
+ { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 860000, 3200000 },
+ { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 870000, 3200000 },
+ { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 880000, 3200000 },
+ { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 890000, 3200000 },
+ { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 900000, 3200000 },
+ { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 910000, 3200000 },
+ { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 920000, 3200000 },
+ { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 930000, 3200000 },
+ { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 940000, 3200000 },
+ { 0, { 1804800, HFPLL, 1, 94 }, L2(19), 955000, 3200000 },
+ { 0, { 1881600, HFPLL, 1, 98 }, L2(19), 965000, 3200000 },
+ { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 975000, 3200000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_2g_pvs6[] __initdata = {
+ { 1, { 300000, PLL_0, 0, 0 }, L2(0), 750000, 400000 },
+ { 0, { 345600, HFPLL, 2, 36 }, L2(3), 750000, 3200000 },
+ { 1, { 422400, HFPLL, 2, 44 }, L2(3), 760000, 3200000 },
+ { 0, { 499200, HFPLL, 2, 52 }, L2(6), 770000, 3200000 },
+ { 1, { 576000, HFPLL, 1, 30 }, L2(6), 780000, 3200000 },
+ { 1, { 652800, HFPLL, 1, 34 }, L2(7), 790000, 3200000 },
+ { 1, { 729600, HFPLL, 1, 38 }, L2(7), 800000, 3200000 },
+ { 0, { 806400, HFPLL, 1, 42 }, L2(10), 810000, 3200000 },
+ { 1, { 883200, HFPLL, 1, 46 }, L2(10), 820000, 3200000 },
+ { 0, { 960000, HFPLL, 1, 50 }, L2(10), 830000, 3200000 },
+ { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 840000, 3200000 },
+ { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 850000, 3200000 },
+ { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 860000, 3200000 },
+ { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 870000, 3200000 },
+ { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 875000, 3200000 },
+ { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 885000, 3200000 },
+ { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 895000, 3200000 },
+ { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 905000, 3200000 },
+ { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 915000, 3200000 },
+ { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 920000, 3200000 },
+ { 0, { 1804800, HFPLL, 1, 94 }, L2(19), 930000, 3200000 },
+ { 0, { 1881600, HFPLL, 1, 98 }, L2(19), 940000, 3200000 },
+ { 1, { 1958400, HFPLL, 1, 102 }, L2(19), 950000, 3200000 },
+ { 0, { 0 } }
+};
+
static struct acpu_level acpu_freq_tbl_2p3g_pvs0[] __initdata = {
{ 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 400000 },
{ 0, { 345600, HFPLL, 2, 36 }, L2(3), 800000, 3200000 },
@@ -339,6 +501,192 @@
{ 0, { 0 } }
};
+static struct acpu_level acpu_freq_tbl_2p3g_pvs1[] __initdata = {
+ { 1, { 300000, PLL_0, 0, 0 }, L2(0), 800000, 400000 },
+ { 0, { 345600, HFPLL, 2, 36 }, L2(3), 800000, 3200000 },
+ { 1, { 422400, HFPLL, 2, 44 }, L2(3), 800000, 3200000 },
+ { 0, { 499200, HFPLL, 2, 52 }, L2(6), 800000, 3200000 },
+ { 1, { 576000, HFPLL, 1, 30 }, L2(6), 800000, 3200000 },
+ { 1, { 652800, HFPLL, 1, 34 }, L2(7), 810000, 3200000 },
+ { 1, { 729600, HFPLL, 1, 38 }, L2(7), 820000, 3200000 },
+ { 0, { 806400, HFPLL, 1, 42 }, L2(10), 830000, 3200000 },
+ { 1, { 883200, HFPLL, 1, 46 }, L2(10), 840000, 3200000 },
+ { 0, { 960000, HFPLL, 1, 50 }, L2(10), 850000, 3200000 },
+ { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 860000, 3200000 },
+ { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 875000, 3200000 },
+ { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 885000, 3200000 },
+ { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 895000, 3200000 },
+ { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 910000, 3200000 },
+ { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 920000, 3200000 },
+ { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 930000, 3200000 },
+ { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 945000, 3200000 },
+ { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 960000, 3200000 },
+ { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 975000, 3200000 },
+ { 0, { 1804800, HFPLL, 1, 94 }, L2(19), 990000, 3200000 },
+ { 0, { 1881600, HFPLL, 1, 98 }, L2(19), 1005000, 3200000 },
+ { 0, { 1958400, HFPLL, 1, 102 }, L2(19), 1020000, 3200000 },
+ { 1, { 2035200, HFPLL, 1, 106 }, L2(19), 1030000, 3200000 },
+ { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1045000, 3200000 },
+ { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1060000, 3200000 },
+ { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1075000, 3200000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_2p3g_pvs2[] __initdata = {
+ { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 400000 },
+ { 0, { 345600, HFPLL, 2, 36 }, L2(3), 775000, 3200000 },
+ { 1, { 422400, HFPLL, 2, 44 }, L2(3), 775000, 3200000 },
+ { 0, { 499200, HFPLL, 2, 52 }, L2(6), 775000, 3200000 },
+ { 1, { 576000, HFPLL, 1, 30 }, L2(6), 785000, 3200000 },
+ { 1, { 652800, HFPLL, 1, 34 }, L2(7), 795000, 3200000 },
+ { 1, { 729600, HFPLL, 1, 38 }, L2(7), 805000, 3200000 },
+ { 0, { 806400, HFPLL, 1, 42 }, L2(10), 815000, 3200000 },
+ { 1, { 883200, HFPLL, 1, 46 }, L2(10), 825000, 3200000 },
+ { 0, { 960000, HFPLL, 1, 50 }, L2(10), 835000, 3200000 },
+ { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 845000, 3200000 },
+ { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 855000, 3200000 },
+ { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 865000, 3200000 },
+ { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 875000, 3200000 },
+ { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 890000, 3200000 },
+ { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 900000, 3200000 },
+ { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 910000, 3200000 },
+ { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 925000, 3200000 },
+ { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 940000, 3200000 },
+ { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 955000, 3200000 },
+ { 0, { 1804800, HFPLL, 1, 94 }, L2(19), 970000, 3200000 },
+ { 0, { 1881600, HFPLL, 1, 98 }, L2(19), 980000, 3200000 },
+ { 0, { 1958400, HFPLL, 1, 102 }, L2(19), 995000, 3200000 },
+ { 1, { 2035200, HFPLL, 1, 106 }, L2(19), 1005000, 3200000 },
+ { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1020000, 3200000 },
+ { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1035000, 3200000 },
+ { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1050000, 3200000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_2p3g_pvs3[] __initdata = {
+ { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 400000 },
+ { 0, { 345600, HFPLL, 2, 36 }, L2(3), 775000, 3200000 },
+ { 1, { 422400, HFPLL, 2, 44 }, L2(3), 775000, 3200000 },
+ { 0, { 499200, HFPLL, 2, 52 }, L2(6), 775000, 3200000 },
+ { 1, { 576000, HFPLL, 1, 30 }, L2(6), 775000, 3200000 },
+ { 1, { 652800, HFPLL, 1, 34 }, L2(7), 780000, 3200000 },
+ { 1, { 729600, HFPLL, 1, 38 }, L2(7), 790000, 3200000 },
+ { 0, { 806400, HFPLL, 1, 42 }, L2(10), 800000, 3200000 },
+ { 1, { 883200, HFPLL, 1, 46 }, L2(10), 810000, 3200000 },
+ { 0, { 960000, HFPLL, 1, 50 }, L2(10), 820000, 3200000 },
+ { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 830000, 3200000 },
+ { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 840000, 3200000 },
+ { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 850000, 3200000 },
+ { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 860000, 3200000 },
+ { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 875000, 3200000 },
+ { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 885000, 3200000 },
+ { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 895000, 3200000 },
+ { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 910000, 3200000 },
+ { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 925000, 3200000 },
+ { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 935000, 3200000 },
+ { 0, { 1804800, HFPLL, 1, 94 }, L2(19), 950000, 3200000 },
+ { 0, { 1881600, HFPLL, 1, 98 }, L2(19), 960000, 3200000 },
+ { 0, { 1958400, HFPLL, 1, 102 }, L2(19), 970000, 3200000 },
+ { 1, { 2035200, HFPLL, 1, 106 }, L2(19), 985000, 3200000 },
+ { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 995000, 3200000 },
+ { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1010000, 3200000 },
+ { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1025000, 3200000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_2p3g_pvs4[] __initdata = {
+ { 1, { 300000, PLL_0, 0, 0 }, L2(0), 775000, 400000 },
+ { 0, { 345600, HFPLL, 2, 36 }, L2(3), 775000, 3200000 },
+ { 1, { 422400, HFPLL, 2, 44 }, L2(3), 775000, 3200000 },
+ { 0, { 499200, HFPLL, 2, 52 }, L2(6), 775000, 3200000 },
+ { 1, { 576000, HFPLL, 1, 30 }, L2(6), 775000, 3200000 },
+ { 1, { 652800, HFPLL, 1, 34 }, L2(7), 775000, 3200000 },
+ { 1, { 729600, HFPLL, 1, 38 }, L2(7), 780000, 3200000 },
+ { 0, { 806400, HFPLL, 1, 42 }, L2(10), 790000, 3200000 },
+ { 1, { 883200, HFPLL, 1, 46 }, L2(10), 800000, 3200000 },
+ { 0, { 960000, HFPLL, 1, 50 }, L2(10), 810000, 3200000 },
+ { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 820000, 3200000 },
+ { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 830000, 3200000 },
+ { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 840000, 3200000 },
+ { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 850000, 3200000 },
+ { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 860000, 3200000 },
+ { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 870000, 3200000 },
+ { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 880000, 3200000 },
+ { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 895000, 3200000 },
+ { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 910000, 3200000 },
+ { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 920000, 3200000 },
+ { 0, { 1804800, HFPLL, 1, 94 }, L2(19), 930000, 3200000 },
+ { 0, { 1881600, HFPLL, 1, 98 }, L2(19), 940000, 3200000 },
+ { 0, { 1958400, HFPLL, 1, 102 }, L2(19), 950000, 3200000 },
+ { 1, { 2035200, HFPLL, 1, 106 }, L2(19), 960000, 3200000 },
+ { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 975000, 3200000 },
+ { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 985000, 3200000 },
+ { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1000000, 3200000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_2p3g_pvs5[] __initdata = {
+ { 1, { 300000, PLL_0, 0, 0 }, L2(0), 750000, 400000 },
+ { 0, { 345600, HFPLL, 2, 36 }, L2(3), 750000, 3200000 },
+ { 1, { 422400, HFPLL, 2, 44 }, L2(3), 750000, 3200000 },
+ { 0, { 499200, HFPLL, 2, 52 }, L2(6), 750000, 3200000 },
+ { 1, { 576000, HFPLL, 1, 30 }, L2(6), 750000, 3200000 },
+ { 1, { 652800, HFPLL, 1, 34 }, L2(7), 760000, 3200000 },
+ { 1, { 729600, HFPLL, 1, 38 }, L2(7), 770000, 3200000 },
+ { 0, { 806400, HFPLL, 1, 42 }, L2(10), 780000, 3200000 },
+ { 1, { 883200, HFPLL, 1, 46 }, L2(10), 790000, 3200000 },
+ { 0, { 960000, HFPLL, 1, 50 }, L2(10), 800000, 3200000 },
+ { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 810000, 3200000 },
+ { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 820000, 3200000 },
+ { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 830000, 3200000 },
+ { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 840000, 3200000 },
+ { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 850000, 3200000 },
+ { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 860000, 3200000 },
+ { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 870000, 3200000 },
+ { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 880000, 3200000 },
+ { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 890000, 3200000 },
+ { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 900000, 3200000 },
+ { 0, { 1804800, HFPLL, 1, 94 }, L2(19), 910000, 3200000 },
+ { 0, { 1881600, HFPLL, 1, 98 }, L2(19), 920000, 3200000 },
+ { 0, { 1958400, HFPLL, 1, 102 }, L2(19), 930000, 3200000 },
+ { 1, { 2035200, HFPLL, 1, 106 }, L2(19), 940000, 3200000 },
+ { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 955000, 3200000 },
+ { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 965000, 3200000 },
+ { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 975000, 3200000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_2p3g_pvs6[] __initdata = {
+ { 1, { 300000, PLL_0, 0, 0 }, L2(0), 750000, 400000 },
+ { 0, { 345600, HFPLL, 2, 36 }, L2(3), 750000, 3200000 },
+ { 1, { 422400, HFPLL, 2, 44 }, L2(3), 750000, 3200000 },
+ { 0, { 499200, HFPLL, 2, 52 }, L2(6), 750000, 3200000 },
+ { 1, { 576000, HFPLL, 1, 30 }, L2(6), 750000, 3200000 },
+ { 1, { 652800, HFPLL, 1, 34 }, L2(7), 750000, 3200000 },
+ { 1, { 729600, HFPLL, 1, 38 }, L2(7), 760000, 3200000 },
+ { 0, { 806400, HFPLL, 1, 42 }, L2(10), 770000, 3200000 },
+ { 1, { 883200, HFPLL, 1, 46 }, L2(10), 780000, 3200000 },
+ { 0, { 960000, HFPLL, 1, 50 }, L2(10), 790000, 3200000 },
+ { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 800000, 3200000 },
+ { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 810000, 3200000 },
+ { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 820000, 3200000 },
+ { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 830000, 3200000 },
+ { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 840000, 3200000 },
+ { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 850000, 3200000 },
+ { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 860000, 3200000 },
+ { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 870000, 3200000 },
+ { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 875000, 3200000 },
+ { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 885000, 3200000 },
+ { 0, { 1804800, HFPLL, 1, 94 }, L2(19), 895000, 3200000 },
+ { 0, { 1881600, HFPLL, 1, 98 }, L2(19), 905000, 3200000 },
+ { 0, { 1958400, HFPLL, 1, 102 }, L2(19), 915000, 3200000 },
+ { 1, { 2035200, HFPLL, 1, 106 }, L2(19), 920000, 3200000 },
+ { 0, { 2112000, HFPLL, 1, 110 }, L2(19), 930000, 3200000 },
+ { 0, { 2188800, HFPLL, 1, 114 }, L2(19), 940000, 3200000 },
+ { 1, { 2265600, HFPLL, 1, 118 }, L2(19), 950000, 3200000 },
+ { 0, { 0 } }
+};
+
static struct pvs_table pvs_v1[NUM_SPEED_BINS][NUM_PVS] __initdata = {
/* 8974v1 1.7GHz Parts */
[0][0] = { acpu_freq_tbl_v1_pvs0, sizeof(acpu_freq_tbl_v1_pvs0) },
@@ -351,23 +699,23 @@
static struct pvs_table pvs_v2[NUM_SPEED_BINS][NUM_PVS] __initdata = {
/* 8974v2 2.0GHz Parts */
[0][0] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
- [0][1] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
- [0][2] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
- [0][3] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
- [0][4] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
- [0][5] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
- [0][6] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
- [0][7] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
+ [0][1] = { acpu_freq_tbl_2g_pvs1, sizeof(acpu_freq_tbl_2g_pvs1) },
+ [0][2] = { acpu_freq_tbl_2g_pvs2, sizeof(acpu_freq_tbl_2g_pvs2) },
+ [0][3] = { acpu_freq_tbl_2g_pvs3, sizeof(acpu_freq_tbl_2g_pvs3) },
+ [0][4] = { acpu_freq_tbl_2g_pvs4, sizeof(acpu_freq_tbl_2g_pvs4) },
+ [0][5] = { acpu_freq_tbl_2g_pvs5, sizeof(acpu_freq_tbl_2g_pvs5) },
+ [0][6] = { acpu_freq_tbl_2g_pvs6, sizeof(acpu_freq_tbl_2g_pvs6) },
+ [0][7] = { acpu_freq_tbl_2g_pvs6, sizeof(acpu_freq_tbl_2g_pvs6) },
/* 8974v2 2.3GHz Parts */
[1][0] = { acpu_freq_tbl_2p3g_pvs0, sizeof(acpu_freq_tbl_2p3g_pvs0) },
- [1][1] = { acpu_freq_tbl_2p3g_pvs0, sizeof(acpu_freq_tbl_2p3g_pvs0) },
- [1][2] = { acpu_freq_tbl_2p3g_pvs0, sizeof(acpu_freq_tbl_2p3g_pvs0) },
- [1][3] = { acpu_freq_tbl_2p3g_pvs0, sizeof(acpu_freq_tbl_2p3g_pvs0) },
- [1][4] = { acpu_freq_tbl_2p3g_pvs0, sizeof(acpu_freq_tbl_2p3g_pvs0) },
- [1][5] = { acpu_freq_tbl_2p3g_pvs0, sizeof(acpu_freq_tbl_2p3g_pvs0) },
- [1][6] = { acpu_freq_tbl_2p3g_pvs0, sizeof(acpu_freq_tbl_2p3g_pvs0) },
- [1][7] = { acpu_freq_tbl_2p3g_pvs0, sizeof(acpu_freq_tbl_2p3g_pvs0) },
+ [1][1] = { acpu_freq_tbl_2p3g_pvs1, sizeof(acpu_freq_tbl_2p3g_pvs1) },
+ [1][2] = { acpu_freq_tbl_2p3g_pvs2, sizeof(acpu_freq_tbl_2p3g_pvs2) },
+ [1][3] = { acpu_freq_tbl_2p3g_pvs3, sizeof(acpu_freq_tbl_2p3g_pvs3) },
+ [1][4] = { acpu_freq_tbl_2p3g_pvs4, sizeof(acpu_freq_tbl_2p3g_pvs4) },
+ [1][5] = { acpu_freq_tbl_2p3g_pvs5, sizeof(acpu_freq_tbl_2p3g_pvs5) },
+ [1][6] = { acpu_freq_tbl_2p3g_pvs6, sizeof(acpu_freq_tbl_2p3g_pvs6) },
+ [1][7] = { acpu_freq_tbl_2p3g_pvs6, sizeof(acpu_freq_tbl_2p3g_pvs6) },
};
static struct msm_bus_scale_pdata bus_scale_data __initdata = {
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 5db52dd..41263f8 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -114,6 +114,29 @@
},
};
+static struct gpiomux_setting lcd_rst_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+ .dir = GPIOMUX_OUT_LOW,
+};
+
+static struct gpiomux_setting lcd_rst_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config msm_lcd_configs[] __initdata = {
+ {
+ .gpio = 25,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &lcd_rst_act_cfg,
+ [GPIOMUX_SUSPENDED] = &lcd_rst_sus_cfg,
+ },
+ }
+};
+
static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
{
.gpio = 0, /* BLSP1 QUP1 SPI_DATA_MOSI */
@@ -225,4 +248,6 @@
msm_gpiomux_install(&sd_card_det, 1);
msm_gpiomux_install(msm_synaptics_configs,
ARRAY_SIZE(msm_synaptics_configs));
+ msm_gpiomux_install_nowrite(msm_lcd_configs,
+ ARRAY_SIZE(msm_lcd_configs));
}
diff --git a/arch/arm/mach-msm/board-8610.c b/arch/arm/mach-msm/board-8610.c
index b4f202d..2723e20 100644
--- a/arch/arm/mach-msm/board-8610.c
+++ b/arch/arm/mach-msm/board-8610.c
@@ -36,6 +36,7 @@
#ifdef CONFIG_ION_MSM
#include <mach/ion.h>
#endif
+#include <linux/regulator/qpnp-regulator.h>
#include <mach/msm_memtypes.h>
#include <mach/socinfo.h>
#include <mach/board.h>
@@ -96,6 +97,7 @@
msm_rpm_driver_init();
msm_lpmrs_module_init();
msm_spm_device_init();
+ qpnp_regulator_init();
msm_thermal_device_init();
if (machine_is_msm8610_rumi())
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 5240f38..d8a9c3e 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -644,7 +644,7 @@
{
.gpio = 25, /* WEBCAM2_RESET_N */
.settings = {
- [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
[GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
},
},
@@ -665,36 +665,36 @@
{
.gpio = 28, /* WEBCAM1_STANDBY */
.settings = {
- [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
[GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
},
},
{
.gpio = 89, /* CAM1_STANDBY_N */
.settings = {
- [GPIOMUX_ACTIVE] = &cam_settings[0],
- [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
},
},
{
.gpio = 90, /* CAM1_RST_N */
.settings = {
- [GPIOMUX_ACTIVE] = &cam_settings[0],
- [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
},
},
{
.gpio = 91, /* CAM2_STANDBY_N */
.settings = {
- [GPIOMUX_ACTIVE] = &cam_settings[0],
- [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
},
},
{
.gpio = 92, /* CAM2_RST_N */
.settings = {
- [GPIOMUX_ACTIVE] = &cam_settings[0],
- [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
},
},
};
diff --git a/arch/arm/mach-msm/boot_stats.c b/arch/arm/mach-msm/boot_stats.c
new file mode 100644
index 0000000..afb4374
--- /dev/null
+++ b/arch/arm/mach-msm/boot_stats.c
@@ -0,0 +1,100 @@
+/* Copyright (c) 2013, 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/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/smp.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/sched.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <mach/msm_iomap.h>
+
+#include "boot_stats.h"
+
+#define MSM_BOOT_STATS_IMEM_START (MSM_IMEM_BASE+0x6b0)
+
+static void __iomem *mpm_counter_base;
+static uint32_t mpm_counter_freq;
+static struct boot_stats *boot_stats =
+ (void __iomem *)(MSM_BOOT_STATS_IMEM_START);
+
+static const struct of_device_id mpm_counter_of_match[] = {
+ { .compatible = "qcom,mpm2-sleep-counter", },
+ {},
+};
+
+static int mpm_parse_dt(void)
+{
+ struct device_node *np;
+ u32 freq;
+
+ np = of_find_matching_node(NULL, mpm_counter_of_match);
+ if (!np) {
+ pr_err("mpm_counter: can't find DT node\n");
+ return -ENODEV;
+ }
+
+ if (!of_property_read_u32(np, "clock-frequency", &freq))
+ mpm_counter_freq = freq;
+ else
+ return -ENODEV;
+
+ if (of_get_address(np, 0, NULL, NULL)) {
+ mpm_counter_base = of_iomap(np, 0);
+ if (!mpm_counter_base) {
+ pr_err("mpm_counter: cant map counter base\n");
+ return -ENODEV;
+ }
+ }
+
+ return 0;
+}
+
+static void print_boot_stats(void)
+{
+ pr_info("KPI: Bootloader start count = %u\n",
+ boot_stats->bootloader_start);
+ pr_info("KPI: Bootloader end count = %u\n",
+ boot_stats->bootloader_end);
+ pr_info("KPI: Bootloader display count = %u\n",
+ boot_stats->bootloader_display);
+ pr_info("KPI: Bootloader load kernel count = %u\n",
+ boot_stats->bootloader_load_kernel);
+ pr_info("KPI: Kernel MPM timestamp = %u\n",
+ __raw_readl(mpm_counter_base));
+ pr_info("KPI: Kernel MPM Clock frequency = %u\n",
+ mpm_counter_freq);
+}
+
+int boot_stats_init(void)
+{
+ int ret;
+
+ if (!boot_stats)
+ return -ENODEV;
+
+ ret = mpm_parse_dt();
+ if (ret < 0)
+ return -ENODEV;
+
+ print_boot_stats();
+
+ return 0;
+}
+
diff --git a/arch/arm/mach-msm/boot_stats.h b/arch/arm/mach-msm/boot_stats.h
new file mode 100644
index 0000000..93e36a2
--- /dev/null
+++ b/arch/arm/mach-msm/boot_stats.h
@@ -0,0 +1,24 @@
+/* Copyright (c) 2013, 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.
+ */
+
+struct boot_stats {
+ uint32_t bootloader_start;
+ uint32_t bootloader_end;
+ uint32_t bootloader_display;
+ uint32_t bootloader_load_kernel;
+};
+
+#ifdef CONFIG_MSM_BOOT_STATS
+int boot_stats_init(void);
+#else
+static inline int boot_stats_init(void) { return 0; }
+#endif
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 5b8ee92..813b210 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -3342,7 +3342,7 @@
"fdc84000.qcom,iommu"),
CLK_LOOKUP("iface_clk", venus0_ahb_clk.c, "fdc84000.qcom,iommu"),
CLK_LOOKUP("core_clk", venus0_axi_clk.c, "fdc84000.qcom,iommu"),
-
+ CLK_LOOKUP("iface_clk", gcc_prng_ahb_clk.c, "f9bff000.qcom,msm-rng"),
CLK_LOOKUP("cam_gp0_clk", camss_gp0_clk.c, ""),
CLK_LOOKUP("cam_gp1_clk", camss_gp1_clk.c, ""),
CLK_LOOKUP("iface_clk", camss_micro_ahb_clk.c, ""),
diff --git a/arch/arm/mach-msm/clock-mdss-8226.c b/arch/arm/mach-msm/clock-mdss-8226.c
new file mode 100644
index 0000000..e7eca7b
--- /dev/null
+++ b/arch/arm/mach-msm/clock-mdss-8226.c
@@ -0,0 +1,346 @@
+/* Copyright (c) 2013, 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/kernel.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/iopoll.h>
+#include <linux/clk.h>
+
+#include <asm/processor.h>
+#include <mach/msm_iomap.h>
+#include <mach/clk-provider.h>
+
+#include "clock-mdss-8226.h"
+
+#define REG_R(addr) readl_relaxed(addr)
+#define REG_W(data, addr) writel_relaxed(data, addr)
+
+#define GDSC_PHYS 0xFD8C2304
+#define GDSC_SIZE 0x4
+
+#define DSI_PHY_PHYS 0xFD922800
+#define DSI_PHY_SIZE 0x00000800
+
+static unsigned char *mdss_dsi_base;
+static unsigned char *gdsc_base;
+static int pll_byte_clk_rate;
+static int pll_pclk_rate;
+static int pll_initialized;
+static struct clk *mdss_dsi_ahb_clk;
+static unsigned long dsi_pll_rate;
+
+void __init mdss_clk_ctrl_pre_init(struct clk *ahb_clk)
+{
+ BUG_ON(ahb_clk == NULL);
+
+ gdsc_base = ioremap(GDSC_PHYS, GDSC_SIZE);
+ if (!gdsc_base)
+ pr_err("%s: unable to remap gdsc base", __func__);
+
+ mdss_dsi_base = ioremap(DSI_PHY_PHYS, DSI_PHY_SIZE);
+ if (!mdss_dsi_base)
+ pr_err("%s: unable to remap dsi base", __func__);
+
+ mdss_dsi_ahb_clk = ahb_clk;
+}
+
+#define PLL_POLL_MAX_READS 10
+#define PLL_POLL_TIMEOUT_US 50
+
+static int mdss_gdsc_enabled(void)
+{
+ if (!gdsc_base)
+ return 0;
+
+ return !!(readl_relaxed(gdsc_base) & BIT(31));
+}
+
+static int mdss_dsi_check_pll_lock(void)
+{
+ u32 status;
+
+ clk_prepare_enable(mdss_dsi_ahb_clk);
+ /* poll for PLL ready status */
+ if (readl_poll_timeout_noirq((mdss_dsi_base + 0x02c0),
+ status,
+ ((status & BIT(0)) == 1),
+ PLL_POLL_MAX_READS, PLL_POLL_TIMEOUT_US)) {
+ pr_err("%s: DSI PLL status=%x failed to Lock\n",
+ __func__, status);
+ pll_initialized = 0;
+ } else {
+ pll_initialized = 1;
+ }
+ clk_disable_unprepare(mdss_dsi_ahb_clk);
+
+ return pll_initialized;
+}
+
+static long mdss_dsi_pll_byte_round_rate(struct clk *c, unsigned long rate)
+{
+ if (pll_initialized) {
+ return pll_byte_clk_rate;
+ } else {
+ pr_err("%s: DSI PLL not configured\n", __func__);
+ return -EINVAL;
+ }
+}
+
+static long mdss_dsi_pll_pixel_round_rate(struct clk *c, unsigned long rate)
+{
+ if (pll_initialized) {
+ return pll_pclk_rate;
+ } else {
+ pr_err("%s: Configure Byte clk first\n", __func__);
+ return -EINVAL;
+ }
+}
+
+static int mdss_dsi_pll_pixel_set_rate(struct clk *c, unsigned long rate)
+{
+ if (pll_initialized) {
+ pll_pclk_rate = (rate * 3) / 2;
+ pr_debug("%s: pll_pclk_rate=%d\n", __func__, pll_pclk_rate);
+ return 0;
+ } else {
+ pr_err("%s: Configure Byte clk first\n", __func__);
+ return -EINVAL;
+ }
+}
+
+static int __mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
+{
+ pr_debug("%s: rate=%ld\n", __func__, rate);
+
+ if (pll_initialized)
+ return 0;
+
+ REG_W(0x70, mdss_dsi_base + 0x0230); /* LPFC1 CFG */
+ REG_W(0x08, mdss_dsi_base + 0x022c); /* LPFR CFG */
+ REG_W(0x02, mdss_dsi_base + 0x0210); /* VREG CFG */
+ REG_W(0x00, mdss_dsi_base + 0x0204); /* postDiv1 */
+ REG_W(0x01, mdss_dsi_base + 0x0200); /* REFCLK CFG */
+ REG_W(0x03, mdss_dsi_base + 0x0224); /* postDiv2 */
+ REG_W(0x00, mdss_dsi_base + 0x0238); /* SDM CFG0 */
+ REG_W(0x0b, mdss_dsi_base + 0x023c); /* SDM CFG1 */
+ REG_W(0x00, mdss_dsi_base + 0x0240); /* SDM CFG2 */
+ REG_W(0x6c, mdss_dsi_base + 0x0244); /* SDM CFG3 */
+ REG_W(0x02, mdss_dsi_base + 0x0208); /* ChgPump */
+ REG_W(0x31, mdss_dsi_base + 0x020c); /* VCOLPF CFG */
+ REG_W(0x15, mdss_dsi_base + 0x0234); /* LPFC2 CFG */
+
+ REG_W(0x30, mdss_dsi_base + 0x0284); /* CAL CFG6 */
+ REG_W(0x00, mdss_dsi_base + 0x0288); /* CAL CFG7 */
+ REG_W(0x60, mdss_dsi_base + 0x028c); /* CAL CFG8 */
+ REG_W(0x00, mdss_dsi_base + 0x0290); /* CAL CFG9 */
+ REG_W(0xdd, mdss_dsi_base + 0x0294); /* CAL CFG10 */
+ REG_W(0x01, mdss_dsi_base + 0x0298); /* CAL CFG11 */
+
+ REG_W(0x03, mdss_dsi_base + 0x0228); /* postDiv3 */
+ REG_W(0x2b, mdss_dsi_base + 0x0278); /* Cal CFG3 */
+ REG_W(0x66, mdss_dsi_base + 0x027c); /* Cal CFG4 */
+ REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDET CFG2 */
+ REG_W(0x00, mdss_dsi_base + 0x0248); /* SDM CFG4 */
+ REG_W(0x00, mdss_dsi_base + 0x0214); /* PWRGEN CFG */
+ REG_W(0x0a, mdss_dsi_base + 0x026c); /* CAL CFG0 */
+ REG_W(0x20, mdss_dsi_base + 0x029c); /* EFUSE CFG */
+
+ dsi_pll_rate = rate;
+ pll_byte_clk_rate = rate;
+
+ pr_debug("%s: PLL initialized. bcl=%d\n", __func__, pll_byte_clk_rate);
+ pll_initialized = 1;
+
+ return 0;
+}
+
+static int mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
+{
+ int ret;
+
+ clk_prepare_enable(mdss_dsi_ahb_clk);
+ ret = __mdss_dsi_pll_byte_set_rate(c, rate);
+ clk_disable_unprepare(mdss_dsi_ahb_clk);
+
+ return ret;
+}
+
+static void mdss_dsi_uniphy_pll_lock_detect_setting(void)
+{
+ REG_W(0x04, mdss_dsi_base + 0x0264); /* LKDetect CFG2 */
+ udelay(100);
+ REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDetect CFG2 */
+ udelay(500);
+}
+
+static void mdss_dsi_uniphy_pll_sw_reset(void)
+{
+ REG_W(0x01, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
+ udelay(1);
+ REG_W(0x00, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
+ udelay(1);
+}
+
+static int __mdss_dsi_pll_enable(struct clk *c)
+{
+ u32 status;
+ u32 max_reads, timeout_us;
+ int i;
+
+ if (!pll_initialized) {
+ if (dsi_pll_rate)
+ __mdss_dsi_pll_byte_set_rate(c, dsi_pll_rate);
+ else
+ pr_err("%s: Calling clk_en before set_rate\n",
+ __func__);
+ }
+
+ mdss_dsi_uniphy_pll_sw_reset();
+ /* PLL power up */
+ /* Add HW recommended delay between
+ register writes for the update to propagate */
+ REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
+ udelay(20);
+ REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
+ udelay(100);
+ REG_W(0x0d, mdss_dsi_base + 0x0220); /* GLB CFG */
+ udelay(20);
+ REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
+ udelay(200);
+
+ for (i = 0; i < 3; i++) {
+ mdss_dsi_uniphy_pll_lock_detect_setting();
+ /* poll for PLL ready status */
+ max_reads = 5;
+ timeout_us = 100;
+ if (readl_poll_timeout_noirq((mdss_dsi_base + 0x02c0),
+ status,
+ ((status & 0x01) == 1),
+ max_reads, timeout_us)) {
+ pr_debug("%s: DSI PLL status=%x failed to Lock\n",
+ __func__, status);
+ pr_debug("%s:Trying to power UP PLL again\n",
+ __func__);
+ } else
+ break;
+
+ mdss_dsi_uniphy_pll_sw_reset();
+ udelay(1000);
+ /* Add HW recommended delay between
+ register writes for the update to propagate */
+ REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
+ udelay(20);
+ REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
+ udelay(100);
+ REG_W(0x0d, mdss_dsi_base + 0x0220); /* GLB CFG */
+ udelay(20);
+ REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
+ udelay(200);
+ }
+
+ if ((status & 0x01) != 1) {
+ pr_err("%s: DSI PLL status=%x failed to Lock\n",
+ __func__, status);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: **** PLL Lock success\n", __func__);
+
+ return 0;
+}
+
+static void __mdss_dsi_pll_disable(void)
+{
+ writel_relaxed(0x00, mdss_dsi_base + 0x0220); /* GLB CFG */
+ pr_debug("%s: **** disable pll Initialize\n", __func__);
+ pll_initialized = 0;
+}
+
+static DEFINE_SPINLOCK(dsipll_lock);
+static int dsipll_refcount;
+
+static void mdss_dsi_pll_disable(struct clk *c)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dsipll_lock, flags);
+ if (WARN(dsipll_refcount == 0, "DSI PLL clock is unbalanced"))
+ goto out;
+ if (dsipll_refcount == 1)
+ __mdss_dsi_pll_disable();
+ dsipll_refcount--;
+out:
+ spin_unlock_irqrestore(&dsipll_lock, flags);
+}
+
+static int mdss_dsi_pll_enable(struct clk *c)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&dsipll_lock, flags);
+ if (dsipll_refcount == 0) {
+ ret = __mdss_dsi_pll_enable(c);
+ if (ret < 0)
+ goto out;
+ }
+ dsipll_refcount++;
+out:
+ spin_unlock_irqrestore(&dsipll_lock, flags);
+ return ret;
+}
+
+/* todo: Adjust these values appropriately */
+static enum handoff mdss_dsi_pll_byte_handoff(struct clk *c)
+{
+ if (mdss_gdsc_enabled() && mdss_dsi_check_pll_lock()) {
+ c->rate = 59000000;
+ dsi_pll_rate = 59000000;
+ pll_byte_clk_rate = 59000000;
+ pll_pclk_rate = 117000000;
+ dsipll_refcount++;
+ return HANDOFF_ENABLED_CLK;
+ }
+
+ return HANDOFF_DISABLED_CLK;
+}
+
+/* todo: Adjust these values appropriately */
+static enum handoff mdss_dsi_pll_pixel_handoff(struct clk *c)
+{
+ if (mdss_gdsc_enabled() && mdss_dsi_check_pll_lock()) {
+ c->rate = 117000000;
+ dsipll_refcount++;
+ return HANDOFF_ENABLED_CLK;
+ }
+
+ return HANDOFF_DISABLED_CLK;
+}
+
+struct clk_ops clk_ops_dsi_pixel_pll = {
+ .enable = mdss_dsi_pll_enable,
+ .disable = mdss_dsi_pll_disable,
+ .set_rate = mdss_dsi_pll_pixel_set_rate,
+ .round_rate = mdss_dsi_pll_pixel_round_rate,
+ .handoff = mdss_dsi_pll_pixel_handoff,
+};
+
+struct clk_ops clk_ops_dsi_byte_pll = {
+ .enable = mdss_dsi_pll_enable,
+ .disable = mdss_dsi_pll_disable,
+ .set_rate = mdss_dsi_pll_byte_set_rate,
+ .round_rate = mdss_dsi_pll_byte_round_rate,
+ .handoff = mdss_dsi_pll_byte_handoff,
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/mach-msm/clock-mdss-8226.h
new file mode 100644
index 0000000..dcf4f92
--- /dev/null
+++ b/arch/arm/mach-msm/clock-mdss-8226.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2013, 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 __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
+#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
+
+extern struct clk_ops clk_ops_dsi_byte_pll;
+extern struct clk_ops clk_ops_dsi_pixel_pll;
+
+void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
+void mdss_clk_ctrl_post_init(void);
+
+#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index 91e96b7..8e7f1fa 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -192,11 +192,12 @@
static int mdss_dsi_pll_pixel_set_rate(struct clk *c, unsigned long rate)
{
- if (pll_initialized)
+ if (pll_initialized) {
+ pll_pclk_rate = (rate * 3) / 2;
+ pr_debug("%s: pll_pclk_rate=%d\n", __func__, pll_pclk_rate);
return 0;
- else {
- pr_err("%s: Configure Byte clk first\n",
- __func__);
+ } else {
+ pr_err("%s: Configure Byte clk first\n", __func__);
return -EINVAL;
}
}
@@ -256,11 +257,9 @@
REG_W(0x20, mdss_dsi_base + 0x029c); /* EFUSE CFG */
dsi_pll_rate = rate;
+ pll_byte_clk_rate = rate;
- pll_byte_clk_rate = 53000000;
- pll_pclk_rate = 105000000;
-
- pr_debug("%s: **** PLL initialized success\n", __func__);
+ pr_debug("%s: PLL initialized. bcl=%d\n", __func__, pll_byte_clk_rate);
pll_initialized = 1;
return 0;
diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h
index d3574c8..8c53ea5 100644
--- a/arch/arm/mach-msm/include/mach/memory.h
+++ b/arch/arm/mach-msm/include/mach/memory.h
@@ -69,7 +69,6 @@
#endif
#ifndef __ASSEMBLY__
-void *alloc_bootmem_aligned(unsigned long size, unsigned long alignment);
void *allocate_contiguous_ebi(unsigned long, unsigned long, int);
unsigned long allocate_contiguous_ebi_nomap(unsigned long, unsigned long);
void clean_and_invalidate_caches(unsigned long, unsigned long, unsigned long);
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index f3bd34a..5f11806 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -107,34 +107,6 @@
outer_inv_range(pstart, pstart + length);
}
-void * __init alloc_bootmem_aligned(unsigned long size, unsigned long alignment)
-{
- void *unused_addr = NULL;
- unsigned long addr, tmp_size, unused_size;
-
- /* Allocate maximum size needed, see where it ends up.
- * Then free it -- in this path there are no other allocators
- * so we can depend on getting the same address back
- * when we allocate a smaller piece that is aligned
- * at the end (if necessary) and the piece we really want,
- * then free the unused first piece.
- */
-
- tmp_size = size + alignment - PAGE_SIZE;
- addr = (unsigned long)alloc_bootmem(tmp_size);
- free_bootmem(__pa(addr), tmp_size);
-
- unused_size = alignment - (addr % alignment);
- if (unused_size)
- unused_addr = alloc_bootmem(unused_size);
-
- addr = (unsigned long)alloc_bootmem(size);
- if (unused_size)
- free_bootmem(__pa(unused_addr), unused_size);
-
- return (void *)addr;
-}
-
char *memtype_name[] = {
"SMI_KERNEL",
"SMI",
diff --git a/arch/arm/mach-msm/msm_mpmctr.c b/arch/arm/mach-msm/msm_mpmctr.c
index 4ab82ab..cc0c1c3 100644
--- a/arch/arm/mach-msm/msm_mpmctr.c
+++ b/arch/arm/mach-msm/msm_mpmctr.c
@@ -54,7 +54,7 @@
}
static struct of_device_id msm_mpmctr_of_match[] = {
- {.compatible = "qcom,mpm-counter"},
+ {.compatible = "qcom,mpm2-sleep-counter"},
{}
};
diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c
index 0579145..7f2f528 100644
--- a/arch/arm/mach-msm/perf_debug.c
+++ b/arch/arm/mach-msm/perf_debug.c
@@ -27,6 +27,7 @@
"2 Perf: Toggle PMU IRQ when CPU's are hotplugged\n"
"3 Perf: Correct irq for CPU hotplug detection\n"
"4 Perf: Check perf activity on correct CPU\n"
+ "5 Perf: Add DT support for L1 and L2 PMU\n"
;
static ssize_t desc_read(struct file *fp, char __user *buf,
diff --git a/arch/arm/mach-msm/perf_event_msm_krait_l2.c b/arch/arm/mach-msm/perf_event_msm_krait_l2.c
index 34b9426..ad34457 100644
--- a/arch/arm/mach-msm/perf_event_msm_krait_l2.c
+++ b/arch/arm/mach-msm/perf_event_msm_krait_l2.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2012 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013 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
@@ -564,6 +564,14 @@
.pmu.attr_groups = msm_l2_pmu_attr_grps,
};
+/*
+ * PMU platform driver and devicetree bindings.
+ */
+static struct of_device_id l2pmu_of_device_ids[] = {
+ {.compatible = "qcom,l2-pmu"},
+ {},
+};
+
static int __devinit krait_l2_pmu_device_probe(struct platform_device *pdev)
{
krait_l2_pmu.plat_device = pdev;
@@ -576,7 +584,8 @@
static struct platform_driver krait_l2_pmu_driver = {
.driver = {
- .name = "l2-arm-pmu",
+ .name = "l2-pmu",
+ .of_match_table = l2pmu_of_device_ids,
},
.probe = krait_l2_pmu_device_probe,
};
diff --git a/arch/arm/mach-msm/perf_event_msm_l2.c b/arch/arm/mach-msm/perf_event_msm_l2.c
index f78487a..efd5e21 100644
--- a/arch/arm/mach-msm/perf_event_msm_l2.c
+++ b/arch/arm/mach-msm/perf_event_msm_l2.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2012 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013 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
@@ -917,7 +917,7 @@
static struct platform_driver scorpion_l2_pmu_driver = {
.driver = {
- .name = "l2-arm-pmu",
+ .name = "l2-pmu",
},
.probe = scorpion_l2_pmu_device_probe,
};
diff --git a/arch/arm/mach-msm/perf_event_msm_pl310.c b/arch/arm/mach-msm/perf_event_msm_pl310.c
index e2a580f..a0d96bf 100644
--- a/arch/arm/mach-msm/perf_event_msm_pl310.c
+++ b/arch/arm/mach-msm/perf_event_msm_pl310.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 ARM Limited
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, 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
@@ -415,9 +415,18 @@
return 0;
}
+/*
+ * PMU platform driver and devicetree bindings.
+ */
+static struct of_device_id l2pmu_of_device_ids[] = {
+ {.compatible = "qcom,l2-pmu"},
+ {},
+};
+
static struct platform_driver l2x0pmu_driver = {
.driver = {
- .name = "l2-arm-pmu",
+ .name = "l2-pmu",
+ .of_match_table = l2pmu_of_device_ids,
},
.probe = l2x0pmu_device_probe,
};
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 7027d1a..8f6c242 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -653,7 +653,7 @@
int64_t time = 0;
if (msm_pm_use_sync_timer)
- return ktime_to_ns(ktime_get());
+ return sched_clock();
time = msm_timer_get_sclk_time(period);
if (!time)
@@ -665,7 +665,7 @@
static int64_t msm_pm_timer_exit_suspend(int64_t time, int64_t period)
{
if (msm_pm_use_sync_timer)
- return ktime_to_ns(ktime_get()) - time;
+ return sched_clock() - time;
if (time != 0) {
int64_t end_time = msm_timer_get_sclk_time(NULL);
diff --git a/arch/arm/mach-msm/pmu.c b/arch/arm/mach-msm/pmu.c
index febeb19..57378c7 100644
--- a/arch/arm/mach-msm/pmu.c
+++ b/arch/arm/mach-msm/pmu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, 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
@@ -15,62 +15,6 @@
#include <mach/irqs.h>
#include <mach/socinfo.h>
-/*
- * If a GIC is present, then all IRQ's < 32 are PPI's and can only be
- * requested and free'd using the percpu IRQ API.
- * If a VIC is present, then only the traditional request, free API works.
- *
- * All MPCore's have GIC's. The Cortex A5 however may or may not be MPcore, but
- * it still has a GIC. Except, the 7x27a, which is an A5 and yet has a VIC.
- * So if the chip is A5 but does not have a GIC, default to the traditional
- * IRQ {request, free}_irq API.
- */
-
-#if defined(CONFIG_ARCH_MSM_KRAITMP) || defined(CONFIG_ARCH_MSM_SCORPIONMP) \
- || defined(CONFIG_ARCH_MSM8625) || \
- (defined(CONFIG_ARCH_MSM_CORTEX_A5) && !defined(CONFIG_MSM_VIC))
-
-static DEFINE_PER_CPU(u32, pmu_irq_cookie);
-
-static int
-multicore_request_irq(int irq, irq_handler_t *handle_irq)
-{
- int err = 0;
- int cpu;
-
- err = request_percpu_irq(irq, *handle_irq, "l1-armpmu",
- &pmu_irq_cookie);
-
- if (!err) {
- for_each_cpu(cpu, cpu_online_mask) {
- smp_call_function_single(cpu,
- enable_irq_callback, &irq, 1);
- }
- }
-
- return err;
-}
-
-static void
-multicore_free_irq(int irq)
-{
- int cpu;
-
- if (irq >= 0) {
- for_each_cpu(cpu, cpu_online_mask) {
- smp_call_function_single(cpu,
- disable_irq_callback, &irq, 1);
- }
- free_percpu_irq(irq, &pmu_irq_cookie);
- }
-}
-
-static struct arm_pmu_platdata multicore_data = {
- .request_pmu_irq = multicore_request_irq,
- .free_pmu_irq = multicore_free_irq,
-};
-#endif
-
static struct resource cpu_pmu_resource[] = {
{
.start = INT_ARMQC_PERFMON,
@@ -89,7 +33,7 @@
};
static struct platform_device l2_pmu_device = {
- .name = "l2-arm-pmu",
+ .name = "l2-pmu",
.id = ARM_PMU_DEVICE_L2CC,
.resource = l2_pmu_resource,
.num_resources = ARRAY_SIZE(l2_pmu_resource),
@@ -98,7 +42,7 @@
#endif
static struct platform_device cpu_pmu_device = {
- .name = "cpu-arm-pmu",
+ .name = "cpu-pmu",
.id = ARM_PMU_DEVICE_CPU,
.resource = cpu_pmu_resource,
.num_resources = ARRAY_SIZE(cpu_pmu_resource),
@@ -120,7 +64,7 @@
};
static struct platform_device msm8625_cpu_pmu_device = {
- .name = "cpu-arm-pmu",
+ .name = "cpu-pmu",
.id = ARM_PMU_DEVICE_CPU,
.resource = msm8625_cpu_pmu_resource,
.num_resources = ARRAY_SIZE(msm8625_cpu_pmu_resource),
@@ -135,7 +79,7 @@
};
static struct platform_device msm8625_l2_pmu_device = {
- .name = "l2-arm-pmu",
+ .name = "l2-pmu",
.id = ARM_PMU_DEVICE_L2CC,
.resource = msm8625_l2_pmu_resource,
.num_resources = ARRAY_SIZE(msm8625_l2_pmu_resource),
@@ -156,7 +100,6 @@
* handlers to call the percpu API.
* Defaults to unicore API {request,free}_irq().
* See arch/arm/kernel/perf_event.c
- * See Comment above on the A5 and MSM_VIC.
*/
#if defined(CONFIG_ARCH_MSM_KRAITMP) || defined(CONFIG_ARCH_MSM_SCORPIONMP) \
|| (defined(CONFIG_ARCH_MSM_CORTEX_A5) && !defined(CONFIG_MSM_VIC))
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 3da1c63..efbd8c6 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -29,6 +29,7 @@
#include <mach/socinfo.h>
#include "smd_private.h"
+#include "boot_stats.h"
#define BUILD_ID_LENGTH 32
@@ -1139,6 +1140,7 @@
if (socinfo->v1.id < ARRAY_SIZE(cpu_of_id))
cur_cpu = cpu_of_id[socinfo->v1.id];
+ boot_stats_init();
socinfo_print();
return 0;
diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h
index 0c6db93..2136f58 100644
--- a/arch/powerpc/include/asm/time.h
+++ b/arch/powerpc/include/asm/time.h
@@ -206,7 +206,5 @@
DECLARE_PER_CPU(u64, decrementers_next_tb);
-extern void decrementer_check_overflow(void);
-
#endif /* __KERNEL__ */
#endif /* __POWERPC_TIME_H */
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index f8df241..2c42cd7 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -769,15 +769,6 @@
clock->name, clock->mult, clock->shift);
}
-void decrementer_check_overflow(void)
-{
- u64 now = get_tb_or_rtc();
- struct decrementer_clock *decrementer = &__get_cpu_var(decrementers);
-
- if (now >= decrementer->next_tb)
- set_dec(1);
-}
-
static int decrementer_set_next_event(unsigned long evt,
struct clock_event_device *dev)
{
diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c
index f34b238..276359e 100644
--- a/arch/sparc/kernel/module.c
+++ b/arch/sparc/kernel/module.c
@@ -20,8 +20,6 @@
#include "entry.h"
-#include "entry.h"
-
#ifdef CONFIG_SPARC64
#include <linux/jump_label.h>
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index f493e52..146bb62 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -749,7 +749,7 @@
*/
const int amd_erratum_400[] =
- AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0x0f, 0x4, 0x2, 0xff, 0xf),
+ AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0xf, 0x41, 0x2, 0xff, 0xf),
AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0xff, 0xf));
EXPORT_SYMBOL_GPL(amd_erratum_400);
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 13e40b9..48be2ad 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -417,6 +417,27 @@
}
static DEVICE_ATTR(wakeup_last_time_ms, 0444, wakeup_last_time_show, NULL);
+
+#ifdef CONFIG_PM_AUTOSLEEP
+static ssize_t wakeup_prevent_sleep_time_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ s64 msec = 0;
+ bool enabled = false;
+
+ spin_lock_irq(&dev->power.lock);
+ if (dev->power.wakeup) {
+ msec = ktime_to_ms(dev->power.wakeup->prevent_sleep_time);
+ enabled = true;
+ }
+ spin_unlock_irq(&dev->power.lock);
+ return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n");
+}
+
+static DEVICE_ATTR(wakeup_prevent_sleep_time_ms, 0444,
+ wakeup_prevent_sleep_time_show, NULL);
+#endif /* CONFIG_PM_AUTOSLEEP */
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM_ADVANCED_DEBUG
@@ -511,6 +532,9 @@
&dev_attr_wakeup_total_time_ms.attr,
&dev_attr_wakeup_max_time_ms.attr,
&dev_attr_wakeup_last_time_ms.attr,
+#ifdef CONFIG_PM_AUTOSLEEP
+ &dev_attr_wakeup_prevent_sleep_time_ms.attr,
+#endif
#endif
NULL,
};
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 1132799..cbb463b 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -133,6 +133,7 @@
spin_lock_init(&ws->lock);
setup_timer(&ws->timer, pm_wakeup_timer_fn, (unsigned long)ws);
ws->active = false;
+ ws->last_time = ktime_get();
spin_lock_irq(&events_lock);
list_add_rcu(&ws->entry, &wakeup_sources);
@@ -380,6 +381,8 @@
ws->active = true;
ws->active_count++;
ws->last_time = ktime_get();
+ if (ws->autosleep_enabled)
+ ws->start_prevent_time = ws->last_time;
/* Increment the counter of events in progress. */
cec = atomic_inc_return(&combined_event_count);
@@ -449,6 +452,17 @@
}
EXPORT_SYMBOL_GPL(pm_stay_awake);
+#ifdef CONFIG_PM_AUTOSLEEP
+static void update_prevent_sleep_time(struct wakeup_source *ws, ktime_t now)
+{
+ ktime_t delta = ktime_sub(now, ws->start_prevent_time);
+ ws->prevent_sleep_time = ktime_add(ws->prevent_sleep_time, delta);
+}
+#else
+static inline void update_prevent_sleep_time(struct wakeup_source *ws,
+ ktime_t now) {}
+#endif
+
/**
* wakup_source_deactivate - Mark given wakeup source as inactive.
* @ws: Wakeup source to handle.
@@ -490,6 +504,9 @@
del_timer(&ws->timer);
ws->timer_expires = 0;
+ if (ws->autosleep_enabled)
+ update_prevent_sleep_time(ws, now);
+
/*
* Increment the counter of registered wakeup events and decrement the
* couter of wakeup events in progress simultaneously.
@@ -660,29 +677,33 @@
/**
* pm_get_wakeup_count - Read the number of registered wakeup events.
* @count: Address to store the value at.
+ * @block: Whether or not to block.
*
- * Store the number of registered wakeup events at the address in @count. Block
- * if the current number of wakeup events being processed is nonzero.
+ * Store the number of registered wakeup events at the address in @count. If
+ * @block is set, block until the current number of wakeup events being
+ * processed is zero.
*
- * Return 'false' if the wait for the number of wakeup events being processed to
- * drop down to zero has been interrupted by a signal (and the current number
- * of wakeup events being processed is still nonzero). Otherwise return 'true'.
+ * Return 'false' if the current number of wakeup events being processed is
+ * nonzero. Otherwise return 'true'.
*/
-bool pm_get_wakeup_count(unsigned int *count)
+bool pm_get_wakeup_count(unsigned int *count, bool block)
{
unsigned int cnt, inpr;
- DEFINE_WAIT(wait);
- for (;;) {
- prepare_to_wait(&wakeup_count_wait_queue, &wait,
- TASK_INTERRUPTIBLE);
- split_counters(&cnt, &inpr);
- if (inpr == 0 || signal_pending(current))
- break;
+ if (block) {
+ DEFINE_WAIT(wait);
- schedule();
+ for (;;) {
+ prepare_to_wait(&wakeup_count_wait_queue, &wait,
+ TASK_INTERRUPTIBLE);
+ split_counters(&cnt, &inpr);
+ if (inpr == 0 || signal_pending(current))
+ break;
+
+ schedule();
+ }
+ finish_wait(&wakeup_count_wait_queue, &wait);
}
- finish_wait(&wakeup_count_wait_queue, &wait);
split_counters(&cnt, &inpr);
*count = cnt;
@@ -714,6 +735,34 @@
return events_check_enabled;
}
+#ifdef CONFIG_PM_AUTOSLEEP
+/**
+ * pm_wakep_autosleep_enabled - Modify autosleep_enabled for all wakeup sources.
+ * @enabled: Whether to set or to clear the autosleep_enabled flags.
+ */
+void pm_wakep_autosleep_enabled(bool set)
+{
+ struct wakeup_source *ws;
+ ktime_t now = ktime_get();
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
+ spin_lock_irq(&ws->lock);
+ if (ws->autosleep_enabled != set) {
+ ws->autosleep_enabled = set;
+ if (ws->active) {
+ if (set)
+ ws->start_prevent_time = now;
+ else
+ update_prevent_sleep_time(ws, now);
+ }
+ }
+ spin_unlock_irq(&ws->lock);
+ }
+ rcu_read_unlock();
+}
+#endif /* CONFIG_PM_AUTOSLEEP */
+
static struct dentry *wakeup_sources_stats_dentry;
/**
@@ -729,28 +778,37 @@
ktime_t max_time;
unsigned long active_count;
ktime_t active_time;
+ ktime_t prevent_sleep_time;
int ret;
spin_lock_irqsave(&ws->lock, flags);
total_time = ws->total_time;
max_time = ws->max_time;
+ prevent_sleep_time = ws->prevent_sleep_time;
active_count = ws->active_count;
if (ws->active) {
- active_time = ktime_sub(ktime_get(), ws->last_time);
+ ktime_t now = ktime_get();
+
+ active_time = ktime_sub(now, ws->last_time);
total_time = ktime_add(total_time, active_time);
if (active_time.tv64 > max_time.tv64)
max_time = active_time;
+
+ if (ws->autosleep_enabled)
+ prevent_sleep_time = ktime_add(prevent_sleep_time,
+ ktime_sub(now, ws->start_prevent_time));
} else {
active_time = ktime_set(0, 0);
}
ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t%lu\t\t"
- "%lld\t\t%lld\t\t%lld\t\t%lld\n",
+ "%lld\t\t%lld\t\t%lld\t\t%lld\t\t%lld\n",
ws->name, active_count, ws->event_count,
ws->wakeup_count, ws->expire_count,
ktime_to_ms(active_time), ktime_to_ms(total_time),
- ktime_to_ms(max_time), ktime_to_ms(ws->last_time));
+ ktime_to_ms(max_time), ktime_to_ms(ws->last_time),
+ ktime_to_ms(prevent_sleep_time));
spin_unlock_irqrestore(&ws->lock, flags);
@@ -767,7 +825,7 @@
seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t"
"expire_count\tactive_since\ttotal_time\tmax_time\t"
- "last_change\n");
+ "last_change\tprevent_suspend_time\n");
rcu_read_lock();
list_for_each_entry_rcu(ws, &wakeup_sources, entry)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index e4b6b6b..ea2f2d2 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -703,8 +703,7 @@
break;
case HCI_ACLDATA_PKT:
- if (!data->bulk_tx_ep || (hdev->conn_hash.acl_num < 1 &&
- hdev->conn_hash.le_num < 1))
+ if (!data->bulk_tx_ep)
return -ENODEV;
urb = usb_alloc_urb(0, GFP_ATOMIC);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index be71347..3d5614b 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -787,6 +787,8 @@
spin_lock_irqsave(&cpufreq_driver_lock, flags);
cpumask_copy(managed_policy->cpus, policy->cpus);
+ cpumask_and(managed_policy->cpus,
+ managed_policy->cpus, cpu_online_mask);
per_cpu(cpufreq_cpu_data, cpu) = managed_policy;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
diff --git a/drivers/crypto/msm/qce.c b/drivers/crypto/msm/qce.c
index 7f8460b..5c1cc5a 100644
--- a/drivers/crypto/msm/qce.c
+++ b/drivers/crypto/msm/qce.c
@@ -505,19 +505,6 @@
return nents;
}
-static int dma_map_pmem_sg(struct buf_info *pmem, unsigned entries,
- struct scatterlist *sg)
-{
- int i = 0;
- for (i = 0; i < entries; i++) {
-
- sg->dma_address = (dma_addr_t)pmem->offset;
- sg++;
- pmem++;
- }
- return 0;
-}
-
static int _probe_ce_engine(struct qce_device *pce_dev)
{
unsigned int val;
@@ -1084,52 +1071,6 @@
return 0;
};
-static int _ablk_cipher_use_pmem_complete(struct qce_device *pce_dev)
-{
- struct ablkcipher_request *areq;
- uint32_t iv_out[4];
- unsigned char iv[4 * sizeof(uint32_t)];
- uint32_t status;
-
- areq = (struct ablkcipher_request *) pce_dev->areq;
-
- /* check ce error status */
- status = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG);
- if (status & (1 << CRYPTO_SW_ERR)) {
- pce_dev->err++;
- dev_err(pce_dev->pdev,
- "Qualcomm Crypto Error at 0x%x, status%x\n",
- pce_dev->phy_iobase, status);
- _init_ce_engine(pce_dev);
- clk_disable(pce_dev->ce_clk);
- pce_dev->qce_cb(areq, NULL, NULL, -ENXIO);
- return 0;
- };
-
- /* get iv out */
- if (pce_dev->mode == QCE_MODE_ECB) {
- clk_disable(pce_dev->ce_clk);
- pce_dev->qce_cb(areq, NULL, NULL, pce_dev->chan_ce_in_status |
- pce_dev->chan_ce_out_status);
- } else {
- iv_out[0] = readl_relaxed(pce_dev->iobase +
- CRYPTO_CNTR0_IV0_REG);
- iv_out[1] = readl_relaxed(pce_dev->iobase +
- CRYPTO_CNTR1_IV1_REG);
- iv_out[2] = readl_relaxed(pce_dev->iobase +
- CRYPTO_CNTR2_IV2_REG);
- iv_out[3] = readl_relaxed(pce_dev->iobase +
- CRYPTO_CNTR3_IV3_REG);
-
- _net_words_to_byte_stream(iv_out, iv, sizeof(iv));
- clk_disable(pce_dev->ce_clk);
- pce_dev->qce_cb(areq, NULL, iv, pce_dev->chan_ce_in_status |
- pce_dev->chan_ce_out_status);
- }
-
- return 0;
-};
-
static int qce_split_and_insert_dm_desc(struct dmov_desc *pdesc,
unsigned int plen, unsigned int paddr, int *index)
{
@@ -1555,53 +1496,6 @@
};
-static void _ablk_cipher_ce_in_call_back_pmem(struct msm_dmov_cmd *cmd_ptr,
- unsigned int result, struct msm_dmov_errdata *err)
-{
- struct qce_device *pce_dev;
-
- pce_dev = (struct qce_device *) cmd_ptr->user;
- if (result != ADM_STATUS_OK) {
- dev_err(pce_dev->pdev, "Qualcomm ADM status error %x\n",
- result);
- pce_dev->chan_ce_in_status = -1;
- } else
- pce_dev->chan_ce_in_status = 0;
-
- pce_dev->chan_ce_in_state = QCE_CHAN_STATE_COMP;
- if (pce_dev->chan_ce_out_state == QCE_CHAN_STATE_COMP) {
- pce_dev->chan_ce_in_state = QCE_CHAN_STATE_IDLE;
- pce_dev->chan_ce_out_state = QCE_CHAN_STATE_IDLE;
-
- /* done */
- _ablk_cipher_use_pmem_complete(pce_dev);
- }
-};
-
-static void _ablk_cipher_ce_out_call_back_pmem(struct msm_dmov_cmd *cmd_ptr,
- unsigned int result, struct msm_dmov_errdata *err)
-{
- struct qce_device *pce_dev;
-
- pce_dev = (struct qce_device *) cmd_ptr->user;
- if (result != ADM_STATUS_OK) {
- dev_err(pce_dev->pdev, "Qualcomm ADM status error %x\n",
- result);
- pce_dev->chan_ce_out_status = -1;
- } else {
- pce_dev->chan_ce_out_status = 0;
- };
-
- pce_dev->chan_ce_out_state = QCE_CHAN_STATE_COMP;
- if (pce_dev->chan_ce_in_state == QCE_CHAN_STATE_COMP) {
- pce_dev->chan_ce_in_state = QCE_CHAN_STATE_IDLE;
- pce_dev->chan_ce_out_state = QCE_CHAN_STATE_IDLE;
-
- /* done */
- _ablk_cipher_use_pmem_complete(pce_dev);
- }
-};
-
static int _setup_cmd_template(struct qce_device *pce_dev)
{
dmov_sg *pcmd;
@@ -2183,14 +2077,9 @@
/* cipher input */
pce_dev->src_nents = count_sg(areq->src, areq->nbytes);
- if (c_req->use_pmem != 1)
- qce_dma_map_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
+ qce_dma_map_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
(areq->src == areq->dst) ? DMA_BIDIRECTIONAL :
DMA_TO_DEVICE);
- else
- dma_map_pmem_sg(&c_req->pmem->src[0], pce_dev->src_nents,
- areq->src);
-
if (_chain_sg_buffer_in(pce_dev, areq->src, areq->nbytes) < 0) {
rc = -ENOMEM;
goto bad;
@@ -2199,12 +2088,8 @@
/* cipher output */
if (areq->src != areq->dst) {
pce_dev->dst_nents = count_sg(areq->dst, areq->nbytes);
- if (c_req->use_pmem != 1)
- qce_dma_map_sg(pce_dev->pdev, areq->dst,
+ qce_dma_map_sg(pce_dev->pdev, areq->dst,
pce_dev->dst_nents, DMA_FROM_DEVICE);
- else
- dma_map_pmem_sg(&c_req->pmem->dst[0],
- pce_dev->dst_nents, areq->dst);
};
if (_chain_sg_buffer_out(pce_dev, areq->dst, areq->nbytes) < 0) {
rc = -ENOMEM;
@@ -2241,34 +2126,25 @@
/* setup for callback, and issue command to adm */
pce_dev->areq = areq;
pce_dev->qce_cb = c_req->qce_cb;
- if (c_req->use_pmem == 1) {
- pce_dev->chan_ce_in_cmd->complete_func =
- _ablk_cipher_ce_in_call_back_pmem;
- pce_dev->chan_ce_out_cmd->complete_func =
- _ablk_cipher_ce_out_call_back_pmem;
- } else {
- pce_dev->chan_ce_in_cmd->complete_func =
+ pce_dev->chan_ce_in_cmd->complete_func =
_ablk_cipher_ce_in_call_back;
- pce_dev->chan_ce_out_cmd->complete_func =
+ pce_dev->chan_ce_out_cmd->complete_func =
_ablk_cipher_ce_out_call_back;
- }
rc = _qce_start_dma(pce_dev, true, true);
if (rc == 0)
return 0;
bad:
- if (c_req->use_pmem != 1) {
- if (pce_dev->dst_nents) {
- qce_dma_unmap_sg(pce_dev->pdev, areq->dst,
- pce_dev->dst_nents, DMA_FROM_DEVICE);
- }
- if (pce_dev->src_nents) {
- qce_dma_unmap_sg(pce_dev->pdev, areq->src,
- pce_dev->src_nents,
- (areq->src == areq->dst) ?
- DMA_BIDIRECTIONAL :
- DMA_TO_DEVICE);
- }
+ if (pce_dev->dst_nents) {
+ qce_dma_unmap_sg(pce_dev->pdev, areq->dst,
+ pce_dev->dst_nents, DMA_FROM_DEVICE);
+ }
+ if (pce_dev->src_nents) {
+ qce_dma_unmap_sg(pce_dev->pdev, areq->src,
+ pce_dev->src_nents,
+ (areq->src == areq->dst) ?
+ DMA_BIDIRECTIONAL :
+ DMA_TO_DEVICE);
}
return rc;
}
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 41ab8dc..2440404 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -12,7 +12,7 @@
* GNU General Public License for more details.
*/
#include <linux/mman.h>
-#include <linux/android_pmem.h>
+
#include <linux/types.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
@@ -454,14 +454,12 @@
/* start the command on the podev->active_command */
qcedev_areq = podev->active_command;
-
qcedev_areq->cipher_req.cookie = qcedev_areq->handle;
- creq.use_pmem = qcedev_areq->cipher_op_req.use_pmem;
- if (qcedev_areq->cipher_op_req.use_pmem == QCEDEV_USE_PMEM)
- creq.pmem = &qcedev_areq->cipher_op_req.pmem;
- else
- creq.pmem = NULL;
-
+ if (qcedev_areq->cipher_op_req.use_pmem == QCEDEV_USE_PMEM) {
+ pr_err("%s: Use of PMEM is not supported\n", __func__);
+ goto unsupported;
+ }
+ creq.pmem = NULL;
switch (qcedev_areq->cipher_op_req.alg) {
case QCEDEV_ALG_DES:
creq.alg = CIPHER_ALG_DES;
@@ -1274,224 +1272,6 @@
return qcedev_hmac_final(areq, handle);
}
-#ifdef CONFIG_ANDROID_PMEM
-static int qcedev_pmem_ablk_cipher_max_xfer(struct qcedev_async_req *areq,
- struct qcedev_handle *handle)
-{
- int i = 0;
- int err = 0;
- struct scatterlist *sg_src = NULL;
- struct scatterlist *sg_dst = NULL;
- struct scatterlist *sg_ndex = NULL;
- struct file *file_src = NULL;
- struct file *file_dst = NULL;
- unsigned long paddr;
- unsigned long kvaddr;
- unsigned long len;
-
- sg_src = kmalloc((sizeof(struct scatterlist) *
- areq->cipher_op_req.entries), GFP_KERNEL);
- if (sg_src == NULL) {
- pr_err("%s: Can't Allocate memory:sg_src 0x%x\n",
- __func__, (uint32_t)sg_src);
- return -ENOMEM;
-
- }
- memset(sg_src, 0, (sizeof(struct scatterlist) *
- areq->cipher_op_req.entries));
- sg_ndex = sg_src;
- areq->cipher_req.creq.src = sg_src;
-
- /* address src */
- get_pmem_file(areq->cipher_op_req.pmem.fd_src, &paddr,
- &kvaddr, &len, &file_src);
-
- for (i = 0; i < areq->cipher_op_req.entries; i++) {
- sg_set_buf(sg_ndex,
- ((uint8_t *)(areq->cipher_op_req.pmem.src[i].offset) + kvaddr),
- areq->cipher_op_req.pmem.src[i].len);
- sg_ndex++;
- }
- sg_mark_end(--sg_ndex);
-
- for (i = 0; i < areq->cipher_op_req.entries; i++)
- areq->cipher_op_req.pmem.src[i].offset += (uint32_t)paddr;
-
- /* address dst */
- /* If not place encryption/decryption */
- if (areq->cipher_op_req.in_place_op != 1) {
- sg_dst = kmalloc((sizeof(struct scatterlist) *
- areq->cipher_op_req.entries), GFP_KERNEL);
- if (sg_dst == NULL) {
- pr_err("%s: Can't Allocate memory: sg_dst 0x%x\n",
- __func__, (uint32_t)sg_dst);
- return -ENOMEM;
- }
- memset(sg_dst, 0, (sizeof(struct scatterlist) *
- areq->cipher_op_req.entries));
- areq->cipher_req.creq.dst = sg_dst;
- sg_ndex = sg_dst;
-
- get_pmem_file(areq->cipher_op_req.pmem.fd_dst, &paddr,
- &kvaddr, &len, &file_dst);
- for (i = 0; i < areq->cipher_op_req.entries; i++)
- sg_set_buf(sg_ndex++,
- ((uint8_t *)(areq->cipher_op_req.pmem.dst[i].offset)
- + kvaddr), areq->cipher_op_req.pmem.dst[i].len);
- sg_mark_end(--sg_ndex);
-
- for (i = 0; i < areq->cipher_op_req.entries; i++)
- areq->cipher_op_req.pmem.dst[i].offset +=
- (uint32_t)paddr;
- } else {
- areq->cipher_req.creq.dst = sg_src;
- for (i = 0; i < areq->cipher_op_req.entries; i++) {
- areq->cipher_op_req.pmem.dst[i].offset =
- areq->cipher_op_req.pmem.src[i].offset;
- areq->cipher_op_req.pmem.dst[i].len =
- areq->cipher_op_req.pmem.src[i].len;
- }
- }
-
- areq->cipher_req.creq.nbytes = areq->cipher_op_req.data_len;
- areq->cipher_req.creq.info = areq->cipher_op_req.iv;
-
- err = submit_req(areq, handle);
-
- kfree(sg_src);
- kfree(sg_dst);
-
- if (file_dst)
- put_pmem_file(file_dst);
- if (file_src)
- put_pmem_file(file_src);
-
- return err;
-};
-
-
-static int qcedev_pmem_ablk_cipher(struct qcedev_async_req *qcedev_areq,
- struct qcedev_handle *handle)
-{
- int err = 0;
- int i = 0;
- int j = 0;
- int k = 0;
- int num_entries = 0;
- uint32_t total = 0;
- struct qcedev_cipher_op_req *saved_req;
- struct qcedev_cipher_op_req *creq = &qcedev_areq->cipher_op_req;
-
- saved_req = kmalloc(sizeof(struct qcedev_cipher_op_req), GFP_KERNEL);
- if (saved_req == NULL) {
- pr_err(KERN_ERR "%s:Can't Allocate mem:saved_req 0x%x\n",
- __func__, (uint32_t)saved_req);
- return -ENOMEM;
- }
- memcpy(saved_req, creq, sizeof(struct qcedev_cipher_op_req));
-
- if (qcedev_areq->cipher_op_req.data_len > QCE_MAX_OPER_DATA) {
-
- struct qcedev_cipher_op_req req;
-
- /* save the original req structure */
- memcpy(&req, creq, sizeof(struct qcedev_cipher_op_req));
-
- i = 0;
- /* Address 32 KB at a time */
- while ((i < req.entries) && (err == 0)) {
- if (creq->pmem.src[i].len > QCE_MAX_OPER_DATA) {
- creq->pmem.src[0].len = QCE_MAX_OPER_DATA;
- if (i > 0) {
- creq->pmem.src[0].offset =
- creq->pmem.src[i].offset;
- }
-
- creq->data_len = QCE_MAX_OPER_DATA;
- creq->entries = 1;
-
- err =
- qcedev_pmem_ablk_cipher_max_xfer(qcedev_areq,
- handle);
-
- creq->pmem.src[i].len = req.pmem.src[i].len -
- QCE_MAX_OPER_DATA;
- creq->pmem.src[i].offset =
- req.pmem.src[i].offset +
- QCE_MAX_OPER_DATA;
- req.pmem.src[i].offset =
- creq->pmem.src[i].offset;
- req.pmem.src[i].len = creq->pmem.src[i].len;
- } else {
- total = 0;
- for (j = i; j < req.entries; j++) {
- num_entries++;
- if ((total + creq->pmem.src[j].len)
- >= QCE_MAX_OPER_DATA) {
- creq->pmem.src[j].len =
- QCE_MAX_OPER_DATA - total;
- total = QCE_MAX_OPER_DATA;
- break;
- }
- total += creq->pmem.src[j].len;
- }
-
- creq->data_len = total;
- if (i > 0)
- for (k = 0; k < num_entries; k++) {
- creq->pmem.src[k].len =
- creq->pmem.src[i+k].len;
- creq->pmem.src[k].offset =
- creq->pmem.src[i+k].offset;
- }
- creq->entries = num_entries;
-
- i = j;
- err =
- qcedev_pmem_ablk_cipher_max_xfer(qcedev_areq,
- handle);
- num_entries = 0;
-
- creq->pmem.src[i].offset =
- req.pmem.src[i].offset +
- creq->pmem.src[i].len;
- creq->pmem.src[i].len =
- req.pmem.src[i].len -
- creq->pmem.src[i].len;
- req.pmem.src[i].offset =
- creq->pmem.src[i].offset;
- req.pmem.src[i].len =
- creq->pmem.src[i].len;
-
- if (creq->pmem.src[i].len == 0)
- i++;
- }
-
- } /* end of while ((i < req.entries) && (err == 0)) */
-
- } else
- err = qcedev_pmem_ablk_cipher_max_xfer(qcedev_areq, handle);
-
- /* Restore the original req structure */
- for (i = 0; i < saved_req->entries; i++) {
- creq->pmem.src[i].len = saved_req->pmem.src[i].len;
- creq->pmem.src[i].offset = saved_req->pmem.src[i].offset;
- }
- creq->entries = saved_req->entries;
- creq->data_len = saved_req->data_len;
- kfree(saved_req);
-
- return err;
-
-}
-#else
-static int qcedev_pmem_ablk_cipher(struct qcedev_async_req *qcedev_areq,
- struct qcedev_handle *handle)
-{
- return -EPERM;
-}
-#endif/*CONFIG_ANDROID_PMEM*/
-
static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq,
int *di, struct qcedev_handle *handle,
uint8_t *k_align_src)
@@ -1753,6 +1533,10 @@
static int qcedev_check_cipher_params(struct qcedev_cipher_op_req *req,
struct qcedev_control *podev)
{
+ if (req->use_pmem) {
+ pr_err("%s: Use of PMEM is not supported\n", __func__);
+ goto error;
+ }
if ((req->entries == 0) || (req->data_len == 0))
goto error;
if ((req->alg >= QCEDEV_ALG_LAST) ||
@@ -1792,15 +1576,6 @@
if (req->byteoffset) {
if (req->mode != QCEDEV_AES_MODE_CTR)
goto error;
- else { /* if using CTR mode make sure not using Pmem */
- if (req->use_pmem)
- goto error;
- }
- }
- /* if using PMEM with non-zero byteoffset, ensure it is in_place_op */
- if (req->use_pmem) {
- if (!req->in_place_op)
- goto error;
}
/* Ensure zer ivlen for ECB mode */
if (req->ivlen != 0) {
@@ -1890,10 +1665,7 @@
podev))
return -EINVAL;
- if (qcedev_areq.cipher_op_req.use_pmem)
- err = qcedev_pmem_ablk_cipher(&qcedev_areq, handle);
- else
- err = qcedev_vbuf_ablk_cipher(&qcedev_areq, handle);
+ err = qcedev_vbuf_ablk_cipher(&qcedev_areq, handle);
if (err)
return err;
if (__copy_to_user((void __user *)arg,
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index b114875..9d24d65 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -3737,10 +3737,6 @@
# define GEN6_RCPBUNIT_CLOCK_GATE_DISABLE (1 << 12)
# define GEN6_RCCUNIT_CLOCK_GATE_DISABLE (1 << 11)
-#define GEN6_UCGCTL2 0x9404
-# define GEN6_RCPBUNIT_CLOCK_GATE_DISABLE (1 << 12)
-# define GEN6_RCCUNIT_CLOCK_GATE_DISABLE (1 << 11)
-
#define GEN6_RPNSWREQ 0xA008
#define GEN6_TURBO_DISABLE (1<<31)
#define GEN6_FREQUENCY(x) ((x)<<25)
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 48dae40..f7eb5d8 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -439,9 +439,6 @@
struct radeon_i2c_chan *ddc_bus;
/* some systems have an hdmi and vga port with a shared ddc line */
bool shared_ddc;
- /* for some Radeon chip families we apply an additional EDID header
- check as part of the DDC probe */
- bool requires_extended_probe;
bool use_digital;
/* we need to mind the EDID between detect
and get modes due to analog/digital/tvencoder */
@@ -529,8 +526,7 @@
u8 val);
extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector);
extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector);
-extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector,
- bool requires_extended_probe);
+extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector);
extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector);
extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector);
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index b1a45bf..bf45a63 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -251,23 +251,19 @@
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
- result = kgsl_mmu_map_global(pagetable, &rb->buffer_desc,
- GSL_PT_PAGE_RV);
+ result = kgsl_mmu_map_global(pagetable, &rb->buffer_desc);
if (result)
goto error;
- result = kgsl_mmu_map_global(pagetable, &rb->memptrs_desc,
- GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+ result = kgsl_mmu_map_global(pagetable, &rb->memptrs_desc);
if (result)
goto unmap_buffer_desc;
- result = kgsl_mmu_map_global(pagetable, &device->memstore,
- GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+ result = kgsl_mmu_map_global(pagetable, &device->memstore);
if (result)
goto unmap_memptrs_desc;
- result = kgsl_mmu_map_global(pagetable, &device->mmu.setstate_memory,
- GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+ result = kgsl_mmu_map_global(pagetable, &device->mmu.setstate_memory);
if (result)
goto unmap_memstore_desc;
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 5cdf911..69b34fa 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -485,6 +485,7 @@
*/
rb->sizedwords = KGSL_RB_SIZE >> 2;
+ rb->buffer_desc.flags = KGSL_MEMFLAGS_GPUREADONLY;
/* allocate memory for ringbuffer */
status = kgsl_allocate_contiguous(&rb->buffer_desc,
(rb->sizedwords << 2));
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 130474a..6e1ecd1 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1871,10 +1871,7 @@
else if (entry->memdesc.size >= SZ_64K)
kgsl_memdesc_set_align(&entry->memdesc, ilog2(SZ_64));
- result = kgsl_mmu_map(private->pagetable,
- &entry->memdesc,
- GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
-
+ result = kgsl_mmu_map(private->pagetable, &entry->memdesc);
if (result)
goto error_put_file_ptr;
@@ -2065,8 +2062,7 @@
if (result)
return result;
- result = kgsl_mmu_map(private->pagetable, &entry->memdesc,
- kgsl_memdesc_protflags(&entry->memdesc));
+ result = kgsl_mmu_map(private->pagetable, &entry->memdesc);
if (result)
goto err;
@@ -2104,8 +2100,7 @@
goto err;
if (!kgsl_memdesc_use_cpu_map(&entry->memdesc)) {
- result = kgsl_mmu_map(private->pagetable, &entry->memdesc,
- kgsl_memdesc_protflags(&entry->memdesc));
+ result = kgsl_mmu_map(private->pagetable, &entry->memdesc);
if (result)
goto err;
}
@@ -2719,8 +2714,7 @@
if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) {
entry->memdesc.gpuaddr = vma->vm_start;
- ret = kgsl_mmu_map(private->pagetable, &entry->memdesc,
- kgsl_memdesc_protflags(&entry->memdesc));
+ ret = kgsl_mmu_map(private->pagetable, &entry->memdesc);
if (ret) {
kgsl_mem_entry_put(entry);
return ret;
@@ -2753,6 +2747,29 @@
}
vma->vm_ops = &kgsl_gpumem_vm_ops;
+
+ if (cache == KGSL_CACHEMODE_WRITEBACK
+ || cache == KGSL_CACHEMODE_WRITETHROUGH) {
+ struct scatterlist *s;
+ int i;
+ int sglen = entry->memdesc.sglen;
+ unsigned long addr = vma->vm_start;
+
+ /* don't map in the guard page, it should always fault */
+ if (kgsl_memdesc_has_guard_page(&entry->memdesc))
+ sglen--;
+
+ for_each_sg(entry->memdesc.sg, s, sglen, i) {
+ int j;
+ for (j = 0; j < (sg_dma_len(s) >> PAGE_SHIFT); j++) {
+ struct page *page = sg_page(s);
+ page = nth_page(page, j);
+ vm_insert_page(vma, addr, page);
+ addr += PAGE_SIZE;
+ }
+ }
+ }
+
vma->vm_file = file;
entry->memdesc.useraddr = vma->vm_start;
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 3eb8831..70a704b 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -149,6 +149,8 @@
#define KGSL_MEMDESC_GUARD_PAGE BIT(0)
/* Set if the memdesc is mapped into all pagetables */
#define KGSL_MEMDESC_GLOBAL BIT(1)
+/* The memdesc is frozen during a snapshot */
+#define KGSL_MEMDESC_FROZEN BIT(2)
/* shared memory allocation */
struct kgsl_memdesc {
@@ -175,15 +177,10 @@
#define KGSL_MEM_ENTRY_ION 4
#define KGSL_MEM_ENTRY_MAX 5
-/* List of flags */
-
-#define KGSL_MEM_ENTRY_FROZEN (1 << 0)
-
struct kgsl_mem_entry {
struct kref refcount;
struct kgsl_memdesc memdesc;
int memtype;
- int flags;
void *priv_data;
struct rb_node node;
unsigned int id;
diff --git a/drivers/gpu/msm/kgsl_drm.c b/drivers/gpu/msm/kgsl_drm.c
index c24e03b..11d6ffa 100644
--- a/drivers/gpu/msm/kgsl_drm.c
+++ b/drivers/gpu/msm/kgsl_drm.c
@@ -210,8 +210,7 @@
return result;
}
- result = kgsl_mmu_map(priv->pagetable, &priv->memdesc,
- GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+ result = kgsl_mmu_map(priv->pagetable, &priv->memdesc);
if (result) {
DRM_ERROR(
"kgsl_mmu_map failed. result = %d\n", result);
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index df8e1d0..93b7e5d 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -43,6 +43,8 @@
{ 0x820, 0, 0 }, /* RESUME */
{ 0x03C, 0, 0 }, /* TLBLKCR */
{ 0x818, 0, 0 }, /* V2PUR */
+ { 0x2C, 0, 0 }, /* FSYNR0 */
+ { 0x2C, 0, 0 }, /* FSYNR0 */
};
static struct kgsl_iommu_register_list kgsl_iommuv1_reg[KGSL_IOMMU_REG_MAX] = {
@@ -51,7 +53,11 @@
{ 0x28, 0x00FFFFFF, 14 }, /* TTBR1 */
{ 0x58, 0, 0 }, /* FSR */
{ 0x618, 0, 0 }, /* TLBIALL */
- { 0x008, 0, 0 } /* RESUME */
+ { 0x008, 0, 0 }, /* RESUME */
+ { 0, 0, 0 }, /* TLBLKCR */
+ { 0, 0, 0 }, /* V2PUR */
+ { 0x68, 0, 0 }, /* FSYNR0 */
+ { 0x6C, 0, 0 } /* FSYNR1 */
};
struct remote_iommu_petersons_spinlock kgsl_iommu_sync_lock_vars;
@@ -118,6 +124,7 @@
unsigned int gpuaddr;
unsigned int size;
unsigned int flags;
+ unsigned int priv;
pid_t pid;
};
@@ -146,7 +153,8 @@
if (entry->memdesc.gpuaddr > ret->gpuaddr) {
ret->gpuaddr = entry->memdesc.gpuaddr;
ret->size = entry->memdesc.size;
- ret->flags = entry->flags;
+ ret->flags = entry->memdesc.flags;
+ ret->priv = entry->memdesc.priv;
ret->pid = priv->pid;
}
@@ -179,7 +187,8 @@
if (entry->memdesc.gpuaddr < ret->gpuaddr) {
ret->gpuaddr = entry->memdesc.gpuaddr;
ret->size = entry->memdesc.size;
- ret->flags = entry->flags;
+ ret->flags = entry->memdesc.flags;
+ ret->priv = entry->memdesc.priv;
ret->pid = priv->pid;
}
@@ -224,9 +233,10 @@
kgsl_get_memory_usage(name, sizeof(name) - 1, entry->flags);
KGSL_LOG_DUMP(device,
- "[%8.8X - %8.8X] (pid = %d) (%s)\n",
+ "[%8.8X - %8.8X] %s (pid = %d) (%s)\n",
entry->gpuaddr,
entry->gpuaddr + entry->size,
+ entry->priv & KGSL_MEMDESC_GUARD_PAGE ? "(+guard)" : "",
entry->pid, name);
}
@@ -275,6 +285,8 @@
unsigned int pid;
struct _mem_entry prev, next;
+ unsigned int fsynr0, fsynr1;
+ int write;
ret = get_iommu_unit(dev, &mmu, &iommu_unit);
if (ret)
@@ -292,12 +304,25 @@
fsr = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
iommu_dev->ctx_id, FSR);
+ fsynr0 = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
+ iommu_dev->ctx_id, FSYNR0);
+ fsynr1 = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
+ iommu_dev->ctx_id, FSYNR1);
+
+ if (msm_soc_version_supports_iommu_v0())
+ write = ((fsynr1 & (KGSL_IOMMU_FSYNR1_AWRITE_MASK <<
+ KGSL_IOMMU_FSYNR1_AWRITE_SHIFT)) ? 1 : 0);
+ else
+ write = ((fsynr0 & (KGSL_IOMMU_V1_FSYNR0_WNR_MASK <<
+ KGSL_IOMMU_V1_FSYNR0_WNR_SHIFT)) ? 1 : 0);
pid = kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase);
KGSL_MEM_CRIT(iommu_dev->kgsldev,
"GPU PAGE FAULT: addr = %lX pid = %d\n", addr, pid);
- KGSL_MEM_CRIT(iommu_dev->kgsldev, "context = %d FSR = %X\n",
- iommu_dev->ctx_id, fsr);
+ KGSL_MEM_CRIT(iommu_dev->kgsldev,
+ "context = %d FSR = %X FSYNR0 = %X FSYNR1 = %X(%s fault)\n",
+ iommu_dev->ctx_id, fsr, fsynr0, fsynr1,
+ write ? "write" : "read");
_check_if_freed(iommu_dev, addr, pid);
@@ -321,7 +346,8 @@
iommu_dev->fault = 1;
trace_kgsl_mmu_pagefault(iommu_dev->kgsldev, addr,
- kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase), 0);
+ kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase),
+ write ? "write" : "read");
/*
* We do not want the h/w to resume fetching data from an iommu unit
@@ -1118,16 +1144,14 @@
for (i = 0; i < iommu->unit_count; i++) {
status = kgsl_mmu_map_global(pt,
- &(iommu->iommu_units[i].reg_map),
- GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+ &(iommu->iommu_units[i].reg_map));
if (status)
goto err;
}
/* Map Lock variables to GPU pagetable */
if (iommu->sync_lock_initialized) {
- status = kgsl_mmu_map_global(pt, &iommu->sync_lock_desc,
- GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+ status = kgsl_mmu_map_global(pt, &iommu->sync_lock_desc);
if (status)
goto err;
}
@@ -1499,25 +1523,39 @@
unsigned int iommu_virt_addr;
struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
int size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
- unsigned int iommu_flags = IOMMU_READ;
BUG_ON(NULL == iommu_pt);
- if (protflags & GSL_PT_PAGE_WV)
- iommu_flags |= IOMMU_WRITE;
+ /* if there's a guard page, we'll map it read only below */
+ if ((protflags & IOMMU_WRITE) && kgsl_memdesc_has_guard_page(memdesc))
+ size -= PAGE_SIZE;
iommu_virt_addr = memdesc->gpuaddr;
ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
- size, iommu_flags);
+ size, protflags);
if (ret) {
- KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
- "failed with err: %d\n", iommu_pt->domain,
- iommu_virt_addr, memdesc->sg, size,
- iommu_flags, ret);
+ KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %x) err: %d\n",
+ iommu_pt->domain, iommu_virt_addr, memdesc->sg, size,
+ protflags, ret);
return ret;
}
+ if ((protflags & IOMMU_WRITE) && kgsl_memdesc_has_guard_page(memdesc)) {
+ struct scatterlist *sg = &memdesc->sg[memdesc->sglen - 1];
+ ret = iommu_map(iommu_pt->domain, iommu_virt_addr + size,
+ kgsl_get_sg_pa(sg), PAGE_SIZE,
+ protflags & ~IOMMU_WRITE);
+ if (ret) {
+ KGSL_CORE_ERR("iommu_map(%p, %x, %x, %x) err: %d\n",
+ iommu_pt->domain, iommu_virt_addr + size,
+ kgsl_get_sg_pa(sg), protflags & ~IOMMU_WRITE,
+ ret);
+ /* cleanup the partial mapping */
+ iommu_unmap_range(iommu_pt->domain, iommu_virt_addr,
+ size);
+ }
+ }
return ret;
}
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index bf40113..c09bc4b 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -19,7 +19,7 @@
#define KGSL_IOMMU_CTX_OFFSET_V1 0x8000
#define KGSL_IOMMU_CTX_SHIFT 12
-/* TLBLKCR feilds */
+/* TLBLKCR fields */
#define KGSL_IOMMU_TLBLKCR_LKE_MASK 0x00000001
#define KGSL_IOMMU_TLBLKCR_LKE_SHIFT 0
#define KGSL_IOMMU_TLBLKCR_TLBIALLCFG_MASK 0x00000001
@@ -33,12 +33,19 @@
#define KGSL_IOMMU_TLBLKCR_VICTIM_MASK 0x000000FF
#define KGSL_IOMMU_TLBLKCR_VICTIM_SHIFT 16
-/* V2PXX feilds */
+/* V2PXX fields */
#define KGSL_IOMMU_V2PXX_INDEX_MASK 0x000000FF
#define KGSL_IOMMU_V2PXX_INDEX_SHIFT 0
#define KGSL_IOMMU_V2PXX_VA_MASK 0x000FFFFF
#define KGSL_IOMMU_V2PXX_VA_SHIFT 12
+/* FSYNR1 V0 fields */
+#define KGSL_IOMMU_FSYNR1_AWRITE_MASK 0x00000001
+#define KGSL_IOMMU_FSYNR1_AWRITE_SHIFT 8
+/* FSYNR0 V1 fields */
+#define KGSL_IOMMU_V1_FSYNR0_WNR_MASK 0x00000001
+#define KGSL_IOMMU_V1_FSYNR0_WNR_SHIFT 4
+
enum kgsl_iommu_reg_map {
KGSL_IOMMU_GLOBAL_BASE = 0,
KGSL_IOMMU_CTX_TTBR0,
@@ -48,6 +55,8 @@
KGSL_IOMMU_CTX_RESUME,
KGSL_IOMMU_CTX_TLBLKCR,
KGSL_IOMMU_CTX_V2PUR,
+ KGSL_IOMMU_CTX_FSYNR0,
+ KGSL_IOMMU_CTX_FSYNR1,
KGSL_IOMMU_REG_MAX
};
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index f71cf8c..83cf83d 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2013, 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
@@ -580,13 +580,13 @@
int
kgsl_mmu_map(struct kgsl_pagetable *pagetable,
- struct kgsl_memdesc *memdesc,
- unsigned int protflags)
+ struct kgsl_memdesc *memdesc)
{
int ret;
struct gen_pool *pool = NULL;
int size;
int page_align = ilog2(PAGE_SIZE);
+ unsigned int protflags = kgsl_memdesc_protflags(memdesc);
if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) {
if (memdesc->sglen == 1) {
@@ -738,7 +738,7 @@
EXPORT_SYMBOL(kgsl_mmu_unmap);
int kgsl_mmu_map_global(struct kgsl_pagetable *pagetable,
- struct kgsl_memdesc *memdesc, unsigned int protflags)
+ struct kgsl_memdesc *memdesc)
{
int result = -EINVAL;
unsigned int gpuaddr = 0;
@@ -750,11 +750,10 @@
/* Not all global mappings are needed for all MMU types */
if (!memdesc->size)
return 0;
-
gpuaddr = memdesc->gpuaddr;
memdesc->priv |= KGSL_MEMDESC_GLOBAL;
- result = kgsl_mmu_map(pagetable, memdesc, protflags);
+ result = kgsl_mmu_map(pagetable, memdesc);
if (result)
goto error;
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 2b33baf..0458a13 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -201,10 +201,9 @@
int kgsl_mmu_start(struct kgsl_device *device);
int kgsl_mmu_close(struct kgsl_device *device);
int kgsl_mmu_map(struct kgsl_pagetable *pagetable,
- struct kgsl_memdesc *memdesc,
- unsigned int protflags);
+ struct kgsl_memdesc *memdesc);
int kgsl_mmu_map_global(struct kgsl_pagetable *pagetable,
- struct kgsl_memdesc *memdesc, unsigned int protflags);
+ struct kgsl_memdesc *memdesc);
int kgsl_mmu_unmap(struct kgsl_pagetable *pagetable,
struct kgsl_memdesc *memdesc);
unsigned int kgsl_virtaddr_to_physaddr(void *virtaddr);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 27b9151..279490f 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2013, 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
@@ -19,6 +19,7 @@
#include "kgsl_mmu.h"
#include <linux/slab.h>
#include <linux/kmemleak.h>
+#include <linux/iommu.h>
#include "kgsl_log.h"
@@ -195,15 +196,24 @@
/*
* kgsl_memdesc_protflags - get mmu protection flags
* @memdesc - the memdesc
- * Returns a mask of GSL_PT_PAGE* values based on the
- * memdesc flags.
+ * Returns a mask of GSL_PT_PAGE* or IOMMU* values based
+ * on the memdesc flags.
*/
static inline unsigned int
kgsl_memdesc_protflags(const struct kgsl_memdesc *memdesc)
{
- unsigned int protflags = GSL_PT_PAGE_RV;
- if (!(memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY))
- protflags |= GSL_PT_PAGE_WV;
+ unsigned int protflags = 0;
+ enum kgsl_mmutype mmutype = kgsl_mmu_get_mmutype();
+
+ if (mmutype == KGSL_MMU_TYPE_GPU) {
+ protflags = GSL_PT_PAGE_RV;
+ if (!(memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY))
+ protflags |= GSL_PT_PAGE_WV;
+ } else if (mmutype == KGSL_MMU_TYPE_IOMMU) {
+ protflags = IOMMU_READ;
+ if (!(memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY))
+ protflags |= IOMMU_WRITE;
+ }
return protflags;
}
@@ -248,8 +258,7 @@
ret = kgsl_sharedmem_page_alloc(memdesc, pagetable, size);
if (ret)
return ret;
- ret = kgsl_mmu_map(pagetable, memdesc,
- kgsl_memdesc_protflags(memdesc));
+ ret = kgsl_mmu_map(pagetable, memdesc);
if (ret)
kgsl_sharedmem_free(memdesc);
return ret;
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 0935f64..c4647a1 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -283,7 +283,7 @@
{
list_del(&obj->node);
- obj->entry->flags &= ~KGSL_MEM_ENTRY_FROZEN;
+ obj->entry->memdesc.priv &= ~KGSL_MEMDESC_FROZEN;
kgsl_mem_entry_put(obj->entry);
kfree(obj);
@@ -416,10 +416,10 @@
* 0 so it doesn't get counted twice
*/
- if (entry->flags & KGSL_MEM_ENTRY_FROZEN)
+ if (entry->memdesc.priv & KGSL_MEMDESC_FROZEN)
return 0;
- entry->flags |= KGSL_MEM_ENTRY_FROZEN;
+ entry->memdesc.priv |= KGSL_MEMDESC_FROZEN;
return entry->memdesc.size;
}
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index e578b0e..f0410d6 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -244,20 +244,17 @@
int result = 0;
struct z180_device *z180_dev = Z180_DEVICE(device);
- result = kgsl_mmu_map_global(pagetable, &device->mmu.setstate_memory,
- GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+ result = kgsl_mmu_map_global(pagetable, &device->mmu.setstate_memory);
if (result)
goto error;
- result = kgsl_mmu_map_global(pagetable, &device->memstore,
- GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+ result = kgsl_mmu_map_global(pagetable, &device->memstore);
if (result)
goto error_unmap_dummy;
result = kgsl_mmu_map_global(pagetable,
- &z180_dev->ringbuffer.cmdbufdesc,
- GSL_PT_PAGE_RV);
+ &z180_dev->ringbuffer.cmdbufdesc);
if (result)
goto error_unmap_memstore;
/*
@@ -498,6 +495,7 @@
struct z180_device *z180_dev = Z180_DEVICE(device);
memset(&z180_dev->ringbuffer, 0, sizeof(struct z180_ringbuffer));
z180_dev->ringbuffer.prevctx = Z180_INVALID_CONTEXT;
+ z180_dev->ringbuffer.cmdbufdesc.flags = KGSL_MEMFLAGS_GPUREADONLY;
return kgsl_allocate_contiguous(&z180_dev->ringbuffer.cmdbufdesc,
Z180_RB_SIZE);
}
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index fda9e0a..3a78489 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -1363,7 +1363,7 @@
int is_eth;
int is_vlan = 0;
int is_grh;
- u16 vlan = 0;
+ u16 vlan;
send_size = 0;
for (i = 0; i < wr->num_sge; ++i)
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
index 0eb0a23..8c484e7 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
@@ -293,8 +293,12 @@
pgmn_dev->jpeg_clk, ARRAY_SIZE(jpeg_8x_clk_info), 0);
fail_clk:
- regulator_put(pgmn_dev->jpeg_fs);
- regulator_disable(pgmn_dev->jpeg_fs);
+ rc = regulator_disable(pgmn_dev->jpeg_fs);
+ if (!rc)
+ regulator_put(pgmn_dev->jpeg_fs);
+ else
+ JPEG_PR_ERR("%s:%d] regulator disable failed %d",
+ __func__, __LINE__, rc);
pgmn_dev->jpeg_fs = NULL;
fail_fs:
@@ -330,8 +334,12 @@
JPEG_DBG("%s:%d] clock disbale done", __func__, __LINE__);
if (pgmn_dev->jpeg_fs) {
- regulator_put(pgmn_dev->jpeg_fs);
- regulator_disable(pgmn_dev->jpeg_fs);
+ result = regulator_disable(pgmn_dev->jpeg_fs);
+ if (!result)
+ regulator_put(pgmn_dev->jpeg_fs);
+ else
+ JPEG_PR_ERR("%s:%d] regulator disable failed %d",
+ __func__, __LINE__, result);
pgmn_dev->jpeg_fs = NULL;
}
iounmap(pgmn_dev->jpeg_vbif);
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 8c30b6c..1b7ecf0 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -164,6 +164,11 @@
}
qinfo = (struct vidc_iface_q_info *) info;
+ if (!qinfo || !qinfo->q_array.align_virtual_addr) {
+ dprintk(VIDC_WARN, "Queues have already been freed\n");
+ return -EINVAL;
+ }
+
venus_hfi_sim_modify_cmd_packet(packet);
queue = (struct hfi_queue_header *) qinfo->q_hdr;
@@ -282,6 +287,10 @@
}
qinfo = (struct vidc_iface_q_info *) info;
+ if (!qinfo || !qinfo->q_array.align_virtual_addr) {
+ dprintk(VIDC_WARN, "Queues have already been freed\n");
+ return -EINVAL;
+ }
queue = (struct hfi_queue_header *) qinfo->q_hdr;
if (!queue) {
@@ -634,6 +643,8 @@
int num_entries = sizeof(venus_qdss_entries)/(2 * sizeof(u32));
int domain, partition;
+ mutex_lock(&device->write_lock);
+ mutex_lock(&device->read_lock);
if (device->qdss.mem_data) {
qdss = (struct hfi_mem_map_table *)
device->qdss.align_virtual_addr;
@@ -674,6 +685,8 @@
msm_smem_delete_client(device->hal_client);
device->hal_client = NULL;
+ mutex_unlock(&device->read_lock);
+ mutex_unlock(&device->write_lock);
}
static int venus_hfi_get_qdss_iommu_virtual_addr(struct hfi_mem_map *mem_map,
int domain, int partition)
@@ -937,7 +950,6 @@
}
dev->intr_status = 0;
- enable_irq(dev->hal_data->irq);
INIT_LIST_HEAD(&dev->sess_head);
mutex_init(&dev->read_lock);
mutex_init(&dev->write_lock);
@@ -966,6 +978,7 @@
rc = -EEXIST;
goto err_core_init;
}
+ enable_irq(dev->hal_data->irq);
venus_hfi_write_register(dev->hal_data->register_base_addr,
VIDC_CTRL_INIT, 0x1, 0);
rc = venus_hfi_core_start_cpu(dev);
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 1f3dc2f..153552d 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -2696,6 +2696,9 @@
{
struct iris_device *radio = video_get_drvdata(video_devdata(file));
int retval = 0;
+ int cf0;
+ struct hci_fm_def_data_rd_req rd;
+ int lsb, msb;
switch (ctrl->id) {
case V4L2_CID_AUDIO_VOLUME:
@@ -2858,6 +2861,113 @@
case V4L2_CID_PRIVATE_VALID_CHANNEL:
ctrl->value = radio->is_station_valid;
break;
+ case V4L2_CID_PRIVATE_AF_RMSSI_TH:
+ rd.mode = FM_RDS_CNFG_MODE;
+ rd.length = FM_RDS_CNFG_LEN;
+ rd.param_len = 0;
+ rd.param = 0;
+
+ retval = hci_def_data_read(&rd, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("Get AF Jump Threshold failed %x", retval);
+ return retval;
+ }
+ lsb = radio->default_data.data[AF_RMSSI_TH_LSB_OFFSET];
+ msb = radio->default_data.data[AF_RMSSI_TH_MSB_OFFSET];
+ ctrl->value = ((msb << 8) | lsb);
+ break;
+ case V4L2_CID_PRIVATE_AF_RMSSI_SAMPLES:
+ rd.mode = FM_RDS_CNFG_MODE;
+ rd.length = FM_RDS_CNFG_LEN;
+ rd.param_len = 0;
+ rd.param = 0;
+
+ retval = hci_def_data_read(&rd, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("Get AF jump rmssi samples failed %x", retval);
+ return retval;
+ }
+ ctrl->value = radio->default_data.data[AF_RMSSI_SAMPLES_OFFSET];
+ break;
+ case V4L2_CID_PRIVATE_GOOD_CH_RMSSI_TH:
+ rd.mode = FM_RX_CONFG_MODE;
+ rd.length = FM_RX_CNFG_LEN;
+ rd.param_len = 0;
+ rd.param = 0;
+
+ retval = hci_def_data_read(&rd, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("get good channel rmssi th failed %x", retval);
+ return retval;
+ }
+ ctrl->value = radio->default_data.data[GD_CH_RMSSI_TH_OFFSET];
+ if (ctrl->value > MAX_GD_CH_RMSSI_TH)
+ ctrl->value -= 256;
+ break;
+ case V4L2_CID_PRIVATE_SRCHALGOTYPE:
+ rd.mode = FM_RX_CONFG_MODE;
+ rd.length = FM_RX_CNFG_LEN;
+ rd.param_len = 0;
+ rd.param = 0;
+
+ retval = hci_def_data_read(&rd, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("get search algo type failed %x", retval);
+ return retval;
+ }
+ ctrl->value = radio->default_data.data[SRCH_ALGO_TYPE_OFFSET];
+ break;
+ case V4L2_CID_PRIVATE_SINRFIRSTSTAGE:
+ rd.mode = FM_RX_CONFG_MODE;
+ rd.length = FM_RX_CNFG_LEN;
+ rd.param_len = 0;
+ rd.param = 0;
+
+ retval = hci_def_data_read(&rd, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("default data read failed %x", retval);
+ return retval;
+ }
+ ctrl->value = radio->default_data.data[SINRFIRSTSTAGE_OFFSET];
+ if (ctrl->value > MAX_SINR_FIRSTSTAGE)
+ ctrl->value -= 256;
+ break;
+ case V4L2_CID_PRIVATE_RMSSIFIRSTSTAGE:
+ rd.mode = FM_RX_CONFG_MODE;
+ rd.length = FM_RX_CNFG_LEN;
+ rd.param_len = 0;
+ rd.param = 0;
+
+ retval = hci_def_data_read(&rd, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("default data read failed %x", retval);
+ return retval;
+ }
+ ctrl->value = radio->default_data.data[RMSSIFIRSTSTAGE_OFFSET];
+ if (ctrl->value > MAX_RMSSI_FIRSTSTAGE)
+ ctrl->value -= 256;
+ break;
+ case V4L2_CID_PRIVATE_CF0TH12:
+ rd.mode = FM_RX_CONFG_MODE;
+ rd.length = FM_RX_CNFG_LEN;
+ rd.param_len = 0;
+ rd.param = 0;
+
+ retval = hci_def_data_read(&rd, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("default data read failed %x", retval);
+ return retval;
+ }
+ ctrl->value = radio->default_data.data[CF0TH12_BYTE1_OFFSET];
+ cf0 = radio->default_data.data[CF0TH12_BYTE2_OFFSET];
+ ctrl->value |= (cf0 << 8);
+ cf0 = radio->default_data.data[CF0TH12_BYTE3_OFFSET];
+ ctrl->value |= (cf0 << 16);
+ cf0 = radio->default_data.data[CF0TH12_BYTE4_OFFSET];
+ if (cf0 > 127)
+ cf0 -= 256;
+ ctrl->value |= (cf0 << 24);
+ break;
default:
retval = -EINVAL;
}
@@ -3022,8 +3132,8 @@
unsigned long arg = 0;
struct hci_fm_tx_ps tx_ps = {0};
struct hci_fm_tx_rt tx_rt = {0};
- struct hci_fm_def_data_rd_req rd_txgain;
- struct hci_fm_def_data_wr_req wr_txgain;
+ struct hci_fm_def_data_rd_req rd;
+ struct hci_fm_def_data_wr_req wrd;
char sinr_th, sinr;
__u8 intf_det_low_th, intf_det_high_th, intf_det_out;
@@ -3325,25 +3435,25 @@
ctrl->value = FM_TX_PWR_LVL_MAX;
if (ctrl->value < FM_TX_PWR_LVL_0)
ctrl->value = FM_TX_PWR_LVL_0;
- rd_txgain.mode = FM_TX_PHY_CFG_MODE;
- rd_txgain.length = FM_TX_PHY_CFG_LEN;
- rd_txgain.param_len = 0x00;
- rd_txgain.param = 0x00;
+ rd.mode = FM_TX_PHY_CFG_MODE;
+ rd.length = FM_TX_PHY_CFG_LEN;
+ rd.param_len = 0x00;
+ rd.param = 0x00;
- retval = hci_def_data_read(&rd_txgain, radio->fm_hdev);
+ retval = hci_def_data_read(&rd, radio->fm_hdev);
if (retval < 0) {
FMDERR("Default data read failed for PHY_CFG %d\n",
retval);
break;
}
- memset(&wr_txgain, 0, sizeof(wr_txgain));
- wr_txgain.mode = FM_TX_PHY_CFG_MODE;
- wr_txgain.length = FM_TX_PHY_CFG_LEN;
- memcpy(&wr_txgain.data, &radio->default_data.data,
+ memset(&wrd, 0, sizeof(wrd));
+ wrd.mode = FM_TX_PHY_CFG_MODE;
+ wrd.length = FM_TX_PHY_CFG_LEN;
+ memcpy(&wrd.data, &radio->default_data.data,
radio->default_data.ret_data_len);
- wr_txgain.data[FM_TX_PWR_GAIN_OFFSET] =
+ wrd.data[FM_TX_PWR_GAIN_OFFSET] =
(ctrl->value) * FM_TX_PWR_LVL_STEP_SIZE;
- retval = hci_def_data_write(&wr_txgain, radio->fm_hdev);
+ retval = hci_def_data_write(&wrd, radio->fm_hdev);
if (retval < 0)
FMDERR("Default write failed for PHY_TXGAIN %d\n",
retval);
@@ -3536,6 +3646,150 @@
else
radio->is_station_valid = INVALID_CHANNEL;
break;
+ case V4L2_CID_PRIVATE_AF_RMSSI_TH:
+ rd.mode = FM_RDS_CNFG_MODE;
+ rd.length = FM_RDS_CNFG_LEN;
+ rd.param_len = 0;
+ rd.param = 0;
+
+ retval = hci_def_data_read(&rd, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("default data read failed %x", retval);
+ return retval;
+ }
+ wrd.mode = FM_RDS_CNFG_MODE;
+ wrd.length = FM_RDS_CNFG_LEN;
+ memcpy(&wrd.data, &radio->default_data.data,
+ radio->default_data.ret_data_len);
+ wrd.data[AF_RMSSI_TH_LSB_OFFSET] = ((ctrl->value) & 255);
+ wrd.data[AF_RMSSI_TH_MSB_OFFSET] = ((ctrl->value) >> 8);
+ retval = hci_def_data_write(&wrd, radio->fm_hdev);
+ if (retval < 0)
+ FMDERR("set AF jump RMSSI threshold failed\n");
+ break;
+ case V4L2_CID_PRIVATE_AF_RMSSI_SAMPLES:
+ rd.mode = FM_RDS_CNFG_MODE;
+ rd.length = FM_RDS_CNFG_LEN;
+ rd.param_len = 0;
+ rd.param = 0;
+
+ retval = hci_def_data_read(&rd, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("default data read failed %x", retval);
+ return retval;
+ }
+ wrd.mode = FM_RDS_CNFG_MODE;
+ wrd.length = FM_RDS_CNFG_LEN;
+ memcpy(&wrd.data, &radio->default_data.data,
+ radio->default_data.ret_data_len);
+ wrd.data[AF_RMSSI_SAMPLES_OFFSET] = ctrl->value;
+ retval = hci_def_data_write(&wrd, radio->fm_hdev);
+ if (retval < 0)
+ FMDERR("set AF jump RMSSI Samples failed\n");
+ break;
+ case V4L2_CID_PRIVATE_GOOD_CH_RMSSI_TH:
+ rd.mode = FM_RX_CONFG_MODE;
+ rd.length = FM_RX_CNFG_LEN;
+ rd.param_len = 0;
+ rd.param = 0;
+
+ retval = hci_def_data_read(&rd, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("default data read failed %x", retval);
+ return retval;
+ }
+ wrd.mode = FM_RX_CONFG_MODE;
+ wrd.length = FM_RX_CNFG_LEN;
+ memcpy(&wrd.data, &radio->default_data.data,
+ radio->default_data.ret_data_len);
+ wrd.data[GD_CH_RMSSI_TH_OFFSET] = ctrl->value;
+ retval = hci_def_data_write(&wrd, radio->fm_hdev);
+ if (retval < 0)
+ FMDERR("set good channel RMSSI th failed\n");
+ break;
+ case V4L2_CID_PRIVATE_SRCHALGOTYPE:
+ rd.mode = FM_RX_CONFG_MODE;
+ rd.length = FM_RX_CNFG_LEN;
+ rd.param_len = 0;
+ rd.param = 0;
+
+ retval = hci_def_data_read(&rd, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("default data read failed %x", retval);
+ return retval;
+ }
+ wrd.mode = FM_RX_CONFG_MODE;
+ wrd.length = FM_RX_CNFG_LEN;
+ memcpy(&wrd.data, &radio->default_data.data,
+ radio->default_data.ret_data_len);
+ wrd.data[SRCH_ALGO_TYPE_OFFSET] = ctrl->value;
+ retval = hci_def_data_write(&wrd, radio->fm_hdev);
+ if (retval < 0)
+ FMDERR("set Search Algo Type failed\n");
+ break;
+ case V4L2_CID_PRIVATE_SINRFIRSTSTAGE:
+ rd.mode = FM_RX_CONFG_MODE;
+ rd.length = FM_RX_CNFG_LEN;
+ rd.param_len = 0;
+ rd.param = 0;
+
+ retval = hci_def_data_read(&rd, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("default data read failed %x", retval);
+ return retval;
+ }
+ wrd.mode = FM_RX_CONFG_MODE;
+ wrd.length = FM_RX_CNFG_LEN;
+ memcpy(&wrd.data, &radio->default_data.data,
+ radio->default_data.ret_data_len);
+ wrd.data[SINRFIRSTSTAGE_OFFSET] = ctrl->value;
+ retval = hci_def_data_write(&wrd, radio->fm_hdev);
+ if (retval < 0)
+ FMDERR("set SINR First Stage failed\n");
+ break;
+ case V4L2_CID_PRIVATE_RMSSIFIRSTSTAGE:
+ rd.mode = FM_RX_CONFG_MODE;
+ rd.length = FM_RX_CNFG_LEN;
+ rd.param_len = 0;
+ rd.param = 0;
+
+ retval = hci_def_data_read(&rd, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("default data read failed %x", retval);
+ return retval;
+ }
+ wrd.mode = FM_RX_CONFG_MODE;
+ wrd.length = FM_RX_CNFG_LEN;
+ memcpy(&wrd.data, &radio->default_data.data,
+ radio->default_data.ret_data_len);
+ wrd.data[RMSSIFIRSTSTAGE_OFFSET] = ctrl->value;
+ retval = hci_def_data_write(&wrd, radio->fm_hdev);
+ if (retval < 0)
+ FMDERR("set RMSSI First Stage failed\n");
+ break;
+ case V4L2_CID_PRIVATE_CF0TH12:
+ rd.mode = FM_RX_CONFG_MODE;
+ rd.length = FM_RX_CNFG_LEN;
+ rd.param_len = 0;
+ rd.param = 0;
+
+ retval = hci_def_data_read(&rd, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("default data read failed %x", retval);
+ return retval;
+ }
+ wrd.mode = FM_RX_CONFG_MODE;
+ wrd.length = FM_RX_CNFG_LEN;
+ memcpy(&wrd.data, &radio->default_data.data,
+ radio->default_data.ret_data_len);
+ wrd.data[CF0TH12_BYTE1_OFFSET] = (ctrl->value & 255);
+ wrd.data[CF0TH12_BYTE2_OFFSET] = ((ctrl->value >> 8) & 255);
+ wrd.data[CF0TH12_BYTE3_OFFSET] = ((ctrl->value >> 16) & 255);
+ wrd.data[CF0TH12_BYTE4_OFFSET] = ((ctrl->value >> 24) & 255);
+ retval = hci_def_data_write(&wrd, radio->fm_hdev);
+ if (retval < 0)
+ FMDERR("set CF0 Threshold failed\n");
+ break;
default:
retval = -EINVAL;
}
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index 8a99968..f3a979b 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -41,7 +41,7 @@
struct rc_dev *rcdev;
struct pm_qos_request pm_qos_req;
struct timer_list gpio_ir_timer;
- unsigned int gpio_nr;
+ int gpio_nr;
bool active_low;
int can_sleep;
bool can_wakeup;
@@ -52,7 +52,7 @@
static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id)
{
struct gpio_rc_dev *gpio_dev = dev_id;
- unsigned int gval;
+ int gval;
int rc = 0;
enum raw_event_type type = IR_SPACE;
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index b2ef948..ff2cddd 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -68,15 +68,6 @@
goto done;
}
- /* Prevent excessive memory consumption, as well as integer
- * overflows.
- */
- if (xmap->menu_count == 0 ||
- xmap->menu_count > UVC_MAX_CONTROL_MENU_ENTRIES) {
- ret = -EINVAL;
- goto done;
- }
-
size = xmap->menu_count * sizeof(*map->menu_info);
map->menu_info = kmalloc(size, GFP_KERNEL);
if (map->menu_info == NULL) {
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 834e0e2..b075435 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -34,6 +34,7 @@
#include <linux/delay.h>
#include <linux/capability.h>
#include <linux/compat.h>
+#include <linux/pm_runtime.h>
#include <linux/mmc/ioctl.h>
#include <linux/mmc/card.h>
@@ -2497,6 +2498,7 @@
#endif
if (req && !mq->mqrq_prev->req) {
+ mmc_rpm_hold(host, &card->dev);
/* claim host only for the first request */
mmc_claim_host(card->host);
if (card->ext_csd.bkops_en)
@@ -2558,6 +2560,7 @@
mmc_start_bkops(card, false);
/* release host only when there are no more requests */
mmc_release_host(card->host);
+ mmc_rpm_release(host, &card->dev);
}
return ret;
}
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index 58efd5e..96e3dc0 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -2695,6 +2695,7 @@
pr_info("%s: Starting tests of card %s...\n",
mmc_hostname(test->card->host), mmc_card_id(test->card));
+ mmc_rpm_hold(test->card->host, &test->card->dev);
mmc_claim_host(test->card->host);
for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) {
@@ -2778,6 +2779,7 @@
}
mmc_release_host(test->card->host);
+ mmc_rpm_release(test->card->host, &test->card->dev);
pr_info("%s: Tests completed.\n",
mmc_hostname(test->card->host));
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 169ccf1..0e024dd 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -57,7 +57,6 @@
{
struct mmc_queue *mq = d;
struct request_queue *q = mq->queue;
- struct request *req;
struct mmc_card *card = mq->card;
current->flags |= PF_MEMALLOC;
@@ -65,7 +64,7 @@
down(&mq->thread_sem);
do {
struct mmc_queue_req *tmp;
- req = NULL; /* Must be set to NULL at each iteration */
+ struct request *req = NULL;
spin_lock_irq(q->queue_lock);
set_current_state(TASK_INTERRUPTIBLE);
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 2f27407..7b9e133 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -26,6 +26,7 @@
#include "bus.h"
#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)
+#define RUNTIME_SUSPEND_DELAY_MS 10000
static ssize_t mmc_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -144,9 +145,6 @@
ret = drv->resume(card);
return ret;
}
-#else
-#define mmc_bus_suspend NULL
-#define mmc_bus_resume NULL
#endif
#ifdef CONFIG_PM_RUNTIME
@@ -155,19 +153,38 @@
{
struct mmc_card *card = mmc_dev_to_card(dev);
- return mmc_power_save_host(card->host);
+ if (mmc_use_core_runtime_pm(card->host))
+ return 0;
+ else
+ return mmc_power_save_host(card->host);
}
static int mmc_runtime_resume(struct device *dev)
{
struct mmc_card *card = mmc_dev_to_card(dev);
- return mmc_power_restore_host(card->host);
+ if (mmc_use_core_runtime_pm(card->host))
+ return 0;
+ else
+ return mmc_power_restore_host(card->host);
}
static int mmc_runtime_idle(struct device *dev)
{
- return pm_runtime_suspend(dev);
+ struct mmc_card *card = mmc_dev_to_card(dev);
+ struct mmc_host *host = card->host;
+ int ret = 0;
+
+ if (mmc_use_core_runtime_pm(card->host)) {
+ ret = pm_schedule_suspend(dev, card->idle_timeout);
+ if (ret) {
+ pr_err("%s: %s: pm_schedule_suspend failed: err: %d\n",
+ mmc_hostname(host), __func__, ret);
+ return ret;
+ }
+ }
+
+ return ret;
}
#endif /* !CONFIG_PM_RUNTIME */
@@ -178,6 +195,42 @@
SET_SYSTEM_SLEEP_PM_OPS(mmc_bus_suspend, mmc_bus_resume)
};
+static ssize_t show_rpm_delay(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct mmc_card *card = mmc_dev_to_card(dev);
+
+ if (!card) {
+ pr_err("%s: %s: card is NULL\n", dev_name(dev), __func__);
+ return -EINVAL;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", card->idle_timeout);
+}
+
+static ssize_t store_rpm_delay(struct device *dev, struct device_attribute
+ *attr, const char *buf, size_t count)
+{
+ struct mmc_card *card = mmc_dev_to_card(dev);
+ unsigned int delay;
+
+ if (!card) {
+ pr_err("%s: %s: card is NULL\n", dev_name(dev), __func__);
+ return -EINVAL;
+ }
+
+ if (!kstrtou32(buf, 0, &delay)) {
+ if (delay < 2000) {
+ pr_err("%s: %s: less than 2 sec delay is unsupported\n",
+ mmc_hostname(card->host), __func__);
+ return -EINVAL;
+ }
+ card->idle_timeout = delay;
+ }
+
+ return count;
+}
+
static struct bus_type mmc_bus_type = {
.name = "mmc",
.dev_attrs = mmc_dev_attrs,
@@ -330,10 +383,34 @@
#endif
mmc_init_context_info(card->host);
+ if (mmc_use_core_runtime_pm(card->host)) {
+ ret = pm_runtime_set_active(&card->dev);
+ if (ret)
+ pr_err("%s: %s: failed setting runtime active: ret: %d\n",
+ mmc_hostname(card->host), __func__, ret);
+ else
+ pm_runtime_enable(&card->dev);
+ }
+
ret = device_add(&card->dev);
if (ret)
return ret;
+ if (mmc_use_core_runtime_pm(card->host)) {
+ card->rpm_attrib.show = show_rpm_delay;
+ card->rpm_attrib.store = store_rpm_delay;
+ sysfs_attr_init(&card->rpm_attrib.attr);
+ card->rpm_attrib.attr.name = "runtime_pm_timeout";
+ card->rpm_attrib.attr.mode = S_IRUGO | S_IWUSR;
+
+ ret = device_create_file(&card->dev, &card->rpm_attrib);
+ if (ret)
+ pr_err("%s: %s: creating runtime pm sysfs entry: failed: %d\n",
+ mmc_hostname(card->host), __func__, ret);
+ /* Default timeout is 10 seconds */
+ card->idle_timeout = RUNTIME_SUSPEND_DELAY_MS;
+ }
+
mmc_card_set_present(card);
return 0;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index a3c3967..07702b4 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -409,9 +409,12 @@
return;
}
+ mmc_rpm_hold(card->host, &card->dev);
/* In case of delayed bkops we might be in race with suspend. */
- if (!mmc_try_claim_host(card->host))
+ if (!mmc_try_claim_host(card->host)) {
+ mmc_rpm_release(card->host, &card->dev);
return;
+ }
/*
* Since the cancel_delayed_work can be changed while we are waiting
@@ -486,6 +489,7 @@
out:
mmc_release_host(card->host);
+ mmc_rpm_release(card->host, &card->dev);
}
EXPORT_SYMBOL(mmc_start_bkops);
@@ -515,6 +519,7 @@
* the host from getting into suspend
*/
do {
+ mmc_rpm_hold(card->host, &card->dev);
mmc_claim_host(card->host);
if (!mmc_card_doing_bkops(card))
@@ -541,6 +546,7 @@
}
mmc_release_host(card->host);
+ mmc_rpm_release(card->host, &card->dev);
/*
* Sleep before checking the card status again to allow the
@@ -559,6 +565,7 @@
return;
out:
mmc_release_host(card->host);
+ mmc_rpm_release(card->host, &card->dev);
}
/**
@@ -2786,8 +2793,9 @@
if (!host->card || !host->bus_ops ||
!host->bus_ops->change_bus_speed ||
!host->clk_scaling.enable || !host->ios.clock)
- goto out;
+ return;
+ mmc_rpm_hold(host, &host->card->dev);
if (!mmc_try_claim_host(host)) {
/* retry after a timer tick */
queue_delayed_work(system_nrt_wq, &host->clk_scaling.work, 1);
@@ -2797,6 +2805,7 @@
mmc_clk_scaling(host, true);
mmc_release_host(host);
out:
+ mmc_rpm_release(host, &host->card->dev);
return;
}
@@ -3020,16 +3029,8 @@
/* Order's important: probe SDIO, then SD, then MMC */
if (!mmc_attach_sdio(host))
return 0;
-
- if (!host->ios.vdd)
- mmc_power_up(host);
-
if (!mmc_attach_sd(host))
return 0;
-
- if (!host->ios.vdd)
- mmc_power_up(host);
-
if (!mmc_attach_mmc(host))
return 0;
@@ -3147,11 +3148,12 @@
if (host->ops->get_cd && host->ops->get_cd(host) == 0)
goto out;
+ mmc_rpm_hold(host, &host->class_dev);
mmc_claim_host(host);
if (!mmc_rescan_try_freq(host, host->f_min))
extend_wakelock = true;
mmc_release_host(host);
-
+ mmc_rpm_release(host, &host->class_dev);
out:
if (extend_wakelock)
wake_lock_timeout(&host->detect_wake_lock, HZ / 2);
@@ -3374,9 +3376,6 @@
if (mmc_bus_needs_resume(host))
return 0;
- cancel_delayed_work(&host->detect);
- mmc_flush_scheduled_work();
-
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) {
/*
@@ -3413,7 +3412,6 @@
* It will be redetected on resume. (Calling
* bus_ops->remove() with a claimed host can
* deadlock.)
- * It will be redetected on resume.
*/
if (host->bus_ops->remove)
host->bus_ops->remove(host);
@@ -3588,6 +3586,37 @@
EXPORT_SYMBOL(mmc_set_embedded_sdio_data);
#endif
+void mmc_rpm_hold(struct mmc_host *host, struct device *dev)
+{
+ int ret = 0;
+
+ if (!mmc_use_core_runtime_pm(host))
+ return;
+
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ pr_err("%s: %s: %s: error resuming device: %d\n",
+ dev_name(dev), mmc_hostname(host), __func__, ret);
+ if (pm_runtime_suspended(dev))
+ BUG_ON(1);
+ }
+}
+EXPORT_SYMBOL(mmc_rpm_hold);
+
+void mmc_rpm_release(struct mmc_host *host, struct device *dev)
+{
+ int ret = 0;
+
+ if (!mmc_use_core_runtime_pm(host))
+ return;
+
+ ret = pm_runtime_put_sync(dev);
+ if (ret < 0 && ret != -EBUSY)
+ pr_err("%s: %s: %s: put sync ret: %d\n",
+ dev_name(dev), mmc_hostname(host), __func__, ret);
+}
+EXPORT_SYMBOL(mmc_rpm_release);
+
/**
* mmc_init_context_info() - init synchronization context
* @host: mmc host
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 0cfddc4..0d7d98b 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -21,6 +21,7 @@
#include <linux/leds.h>
#include <linux/slab.h>
#include <linux/suspend.h>
+#include <linux/pm_runtime.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
@@ -37,9 +38,73 @@
kfree(host);
}
+static int mmc_host_runtime_suspend(struct device *dev)
+{
+ struct mmc_host *host = cls_dev_to_mmc_host(dev);
+ int ret = 0;
+
+ ret = mmc_suspend_host(host);
+ if (ret < 0)
+ pr_err("%s: %s: suspend host failed: %d\n", mmc_hostname(host),
+ __func__, ret);
+
+ return ret;
+}
+
+static int mmc_host_runtime_resume(struct device *dev)
+{
+ struct mmc_host *host = cls_dev_to_mmc_host(dev);
+ int ret = 0;
+
+ ret = mmc_resume_host(host);
+ if (ret < 0) {
+ pr_err("%s: %s: resume host: failed: ret: %d\n",
+ mmc_hostname(host), __func__, ret);
+ if (pm_runtime_suspended(dev))
+ BUG_ON(1);
+ }
+
+ return ret;
+}
+
+static int mmc_host_suspend(struct device *dev)
+{
+ struct mmc_host *host = cls_dev_to_mmc_host(dev);
+ int ret = 0;
+
+ if (!pm_runtime_suspended(dev)) {
+ ret = mmc_suspend_host(host);
+ if (ret < 0)
+ pr_err("%s: %s: failed: ret: %d\n", mmc_hostname(host),
+ __func__, ret);
+ }
+ return ret;
+}
+
+static int mmc_host_resume(struct device *dev)
+{
+ struct mmc_host *host = cls_dev_to_mmc_host(dev);
+ int ret = 0;
+
+ if (!pm_runtime_suspended(dev)) {
+ ret = mmc_resume_host(host);
+ if (ret < 0)
+ pr_err("%s: %s: failed: ret: %d\n", mmc_hostname(host),
+ __func__, ret);
+ }
+ return ret;
+}
+
+static const struct dev_pm_ops mmc_host_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mmc_host_suspend, mmc_host_resume)
+ SET_RUNTIME_PM_OPS(mmc_host_runtime_suspend, mmc_host_runtime_resume,
+ pm_generic_runtime_idle)
+};
+
static struct class mmc_host_class = {
.name = "mmc_host",
.dev_release = mmc_host_classdev_release,
+ .pm = &mmc_host_pm_ops,
};
int mmc_register_host_class(void)
@@ -60,8 +125,7 @@
struct device_attribute *attr, char *buf)
{
struct mmc_host *host = cls_dev_to_mmc_host(dev);
- return snprintf(buf, PAGE_SIZE, "%lu\n",
- host->clkgate_delay);
+ return snprintf(buf, PAGE_SIZE, "%lu\n", host->clkgate_delay);
}
static ssize_t clkgate_delay_store(struct device *dev,
@@ -76,9 +140,6 @@
spin_lock_irqsave(&host->clk_lock, flags);
host->clkgate_delay = value;
spin_unlock_irqrestore(&host->clk_lock, flags);
-
- pr_info("%s: clock gate delay set to %lu ms\n",
- mmc_hostname(host), value);
return count;
}
@@ -533,7 +594,7 @@
static ssize_t
show_perf(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct mmc_host *host = dev_get_drvdata(dev);
+ struct mmc_host *host = cls_dev_to_mmc_host(dev);
int64_t rtime_drv, wtime_drv;
unsigned long rbytes_drv, wbytes_drv;
@@ -559,8 +620,8 @@
set_perf(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
+ struct mmc_host *host = cls_dev_to_mmc_host(dev);
int64_t value;
- struct mmc_host *host = dev_get_drvdata(dev);
sscanf(buf, "%lld", &value);
spin_lock(&host->lock);
@@ -605,6 +666,14 @@
WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
!host->ops->enable_sdio_irq);
+ if (mmc_use_core_runtime_pm(host)) {
+ err = pm_runtime_set_active(&host->class_dev);
+ if (err)
+ pr_err("%s: %s: failed setting runtime active: err: %d\n",
+ mmc_hostname(host), __func__, err);
+ else
+ pm_runtime_enable(&host->class_dev);
+ }
err = device_add(&host->class_dev);
if (err)
return err;
@@ -625,7 +694,7 @@
pr_err("%s: failed to create clk scale sysfs group with err %d\n",
__func__, err);
- err = sysfs_create_group(&host->parent->kobj, &dev_attr_grp);
+ err = sysfs_create_group(&host->class_dev.kobj, &dev_attr_grp);
if (err)
pr_err("%s: failed to create sysfs group with err %d\n",
__func__, err);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 0e6956f..8a866cf 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -17,6 +17,7 @@
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
+#include <linux/pm_runtime.h>
#include "core.h"
#include "bus.h"
@@ -293,7 +294,7 @@
card->ext_csd.rev = ext_csd[EXT_CSD_REV];
if (card->ext_csd.rev > 7) {
- printk(KERN_ERR "%s: unrecognised EXT_CSD revision %d\n",
+ pr_err("%s: unrecognised EXT_CSD revision %d\n",
mmc_hostname(card->host), card->ext_csd.rev);
err = -EINVAL;
goto out;
@@ -1495,6 +1496,7 @@
BUG_ON(!host);
BUG_ON(!host->card);
+ mmc_rpm_hold(host, &host->card->dev);
mmc_claim_host(host);
/*
@@ -1504,6 +1506,13 @@
mmc_release_host(host);
+ /*
+ * if detect fails, the device would be removed anyway;
+ * the rpm framework would mark the device state suspended.
+ */
+ if (!err)
+ mmc_rpm_release(host, &host->card->dev);
+
if (err) {
mmc_remove(host);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 318d590..dc129f7 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -18,6 +18,7 @@
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>
+#include <linux/pm_runtime.h>
#include "core.h"
#include "bus.h"
@@ -944,9 +945,9 @@
int ro = -1;
if (host->ops->get_ro) {
- mmc_host_clk_hold(host);
+ mmc_host_clk_hold(card->host);
ro = host->ops->get_ro(host);
- mmc_host_clk_release(host);
+ mmc_host_clk_release(card->host);
}
if (ro < 0) {
@@ -1067,9 +1068,9 @@
* value registers for UHS-I cards.
*/
if (host->ops->enable_preset_value) {
- mmc_host_clk_hold(host);
+ mmc_host_clk_hold(card->host);
host->ops->enable_preset_value(host, true);
- mmc_host_clk_release(host);
+ mmc_host_clk_release(card->host);
}
} else {
/*
@@ -1145,7 +1146,8 @@
BUG_ON(!host);
BUG_ON(!host->card);
-
+
+ mmc_rpm_hold(host, &host->card->dev);
mmc_claim_host(host);
/*
@@ -1170,6 +1172,13 @@
#endif
mmc_release_host(host);
+ /*
+ * if detect fails, the device would be removed anyway;
+ * the rpm framework would mark the device state suspended.
+ */
+ if (!err)
+ mmc_rpm_release(host, &host->card->dev);
+
if (err) {
mmc_sd_remove(host);
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 1c4697d..56d4499 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -1389,8 +1389,6 @@
dto -= 13;
else
dto = 0;
- /* Use the maximum timeout value allowed in the standard of 14
- or 0xE */
if (dto > 14)
dto = 14;
}
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 27e6c79..7bae401 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -32,6 +32,9 @@
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/mmc/mmc.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/mmc/cd-gpio.h>
#include <mach/gpio.h>
#include <mach/msm_bus.h>
@@ -200,6 +203,7 @@
bool nonremovable;
struct sdhci_msm_pin_data *pin_data;
u32 cpu_dma_latency_us;
+ int status_gpio; /* card detection GPIO that is configured as IRQ */
struct sdhci_msm_bus_voting_data *voting_data;
};
@@ -216,6 +220,7 @@
struct sdhci_msm_host {
struct platform_device *pdev;
void __iomem *core_mem; /* MSM SDCC mapped address */
+ int pwr_irq; /* power irq */
struct clk *clk; /* main SD/MMC bus clock */
struct clk *pclk; /* SDHC peripheral bus clock */
struct clk *bus_clk; /* SDHC bus voter clock */
@@ -1075,6 +1080,8 @@
goto out;
}
+ pdata->status_gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, 0);
+
of_property_read_u32(np, "qcom,bus-width", &bus_width);
if (bus_width == 8)
pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
@@ -1864,7 +1871,7 @@
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_msm_host *msm_host;
struct resource *core_memres = NULL;
- int ret = 0, pwr_irq = 0, dead = 0;
+ int ret = 0, dead = 0;
u32 vdd_max_current;
u32 host_version;
@@ -1987,18 +1994,18 @@
}
/* Setup PWRCTL irq */
- pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
- if (pwr_irq < 0) {
+ msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
+ if (msm_host->pwr_irq < 0) {
dev_err(&pdev->dev, "Failed to get pwr_irq by name (%d)\n",
- pwr_irq);
+ msm_host->pwr_irq);
goto vreg_deinit;
}
- ret = devm_request_threaded_irq(&pdev->dev, pwr_irq, NULL,
+ ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL,
sdhci_msm_pwr_irq, IRQF_ONESHOT,
dev_name(&pdev->dev), host);
if (ret) {
dev_err(&pdev->dev, "Request threaded irq(%d) failed (%d)\n",
- pwr_irq, ret);
+ msm_host->pwr_irq, ret);
goto vreg_deinit;
}
@@ -2029,6 +2036,7 @@
msm_host->mmc->caps |= MMC_CAP_HW_RESET;
msm_host->mmc->caps2 |= msm_host->pdata->caps2;
+ msm_host->mmc->caps2 |= MMC_CAP2_CORE_RUNTIME_PM;
msm_host->mmc->caps2 |= MMC_CAP2_PACKED_WR;
msm_host->mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
msm_host->mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC |
@@ -2051,10 +2059,20 @@
INIT_DELAYED_WORK(&msm_host->msm_bus_vote.vote_work,
sdhci_msm_bus_work);
+ if (gpio_is_valid(msm_host->pdata->status_gpio)) {
+ ret = mmc_cd_gpio_request(msm_host->mmc,
+ msm_host->pdata->status_gpio);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: Failed to request card detection IRQ %d\n",
+ __func__, ret);
+ goto bus_unregister;
+ }
+ }
+
ret = sdhci_add_host(host);
if (ret) {
dev_err(&pdev->dev, "Add host failed (%d)\n", ret);
- goto bus_unregister;
+ goto free_cd_gpio;
}
/* Set core clk rate, optionally override from dts */
@@ -2076,12 +2094,22 @@
if (ret)
goto remove_host;
+ ret = pm_runtime_set_active(&pdev->dev);
+ if (ret)
+ pr_err("%s: %s: pm_runtime_set_active failed: err: %d\n",
+ mmc_hostname(host->mmc), __func__, ret);
+ else
+ pm_runtime_enable(&pdev->dev);
+
/* Successful initialization */
goto out;
remove_host:
dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
sdhci_remove_host(host, dead);
+free_cd_gpio:
+ if (gpio_is_valid(msm_host->pdata->status_gpio))
+ mmc_cd_gpio_free(msm_host->mmc);
bus_unregister:
sdhci_msm_bus_unregister(msm_host);
vreg_deinit:
@@ -2114,7 +2142,12 @@
pr_debug("%s: %s\n", dev_name(&pdev->dev), __func__);
device_remove_file(&pdev->dev, &msm_host->msm_bus_vote.max_bus_bw);
sdhci_remove_host(host, dead);
+ pm_runtime_disable(&pdev->dev);
sdhci_pltfm_free(pdev);
+
+ if (gpio_is_valid(msm_host->pdata->status_gpio))
+ mmc_cd_gpio_free(msm_host->mmc);
+
sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false);
if (pdata->pin_data)
@@ -2127,6 +2160,92 @@
return 0;
}
+static int sdhci_msm_runtime_suspend(struct device *dev)
+{
+ struct sdhci_host *host = dev_get_drvdata(dev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+
+ disable_irq(host->irq);
+ disable_irq(msm_host->pwr_irq);
+
+ return 0;
+}
+
+static int sdhci_msm_runtime_resume(struct device *dev)
+{
+ struct sdhci_host *host = dev_get_drvdata(dev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+
+ enable_irq(msm_host->pwr_irq);
+ enable_irq(host->irq);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int sdhci_msm_suspend(struct device *dev)
+{
+ struct sdhci_host *host = dev_get_drvdata(dev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ int ret = 0;
+
+ if (gpio_is_valid(msm_host->pdata->status_gpio))
+ mmc_cd_gpio_free(msm_host->mmc);
+
+ if (pm_runtime_suspended(dev)) {
+ pr_debug("%s: %s: already runtime suspended\n",
+ mmc_hostname(host->mmc), __func__);
+ goto out;
+ }
+
+ return sdhci_msm_runtime_suspend(dev);
+out:
+ return ret;
+}
+
+static int sdhci_msm_resume(struct device *dev)
+{
+ struct sdhci_host *host = dev_get_drvdata(dev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ int ret = 0;
+
+ if (gpio_is_valid(msm_host->pdata->status_gpio)) {
+ ret = mmc_cd_gpio_request(msm_host->mmc,
+ msm_host->pdata->status_gpio);
+ if (ret)
+ pr_err("%s: %s: Failed to request card detection IRQ %d\n",
+ mmc_hostname(host->mmc), __func__, ret);
+ }
+
+ if (pm_runtime_suspended(dev)) {
+ pr_debug("%s: %s: runtime suspended, defer system resume\n",
+ mmc_hostname(host->mmc), __func__);
+ goto out;
+ }
+
+ return sdhci_msm_runtime_resume(dev);
+out:
+ return ret;
+}
+#endif
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops sdhci_msm_pmops = {
+ SET_SYSTEM_SLEEP_PM_OPS(sdhci_msm_suspend, sdhci_msm_resume)
+ SET_RUNTIME_PM_OPS(sdhci_msm_runtime_suspend, sdhci_msm_runtime_resume,
+ NULL)
+};
+
+#define SDHCI_MSM_PMOPS (&sdhci_msm_pmops)
+
+#else
+#define SDHCI_PM_OPS NULL
+#endif
static const struct of_device_id sdhci_msm_dt_match[] = {
{.compatible = "qcom,sdhci-msm"},
};
@@ -2139,6 +2258,7 @@
.name = "sdhci_msm",
.owner = THIS_MODULE,
.of_match_table = sdhci_msm_dt_match,
+ .pm = SDHCI_MSM_PMOPS,
},
};
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index e7a3741..69ef0be 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -23,9 +23,8 @@
#include <linux/scatterlist.h>
#include <linux/io.h>
#include <linux/gpio.h>
-#include <linux/mmc/sdhci-pci-data.h>
-#include <linux/sfi.h>
#include <linux/pm_runtime.h>
+#include <linux/mmc/sdhci-pci-data.h>
#include "sdhci.h"
@@ -368,8 +367,6 @@
pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
}
- slot->host->mmc->caps2 = MMC_CAP2_BOOTPART_NOACC;
-
return 0;
}
@@ -1452,8 +1449,6 @@
int i;
struct sdhci_pci_chip *chip;
- sdhci_pci_runtime_pm_forbid(&pdev->dev);
-
chip = pci_get_drvdata(pdev);
if (chip) {
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 97c1013..0a89ea2 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -453,6 +453,44 @@
dataddr[0] = cpu_to_le32(addr);
}
+static int sdhci_pre_dma_transfer(struct sdhci_host *host,
+ struct mmc_data *data,
+ struct sdhci_next *next)
+{
+ int sg_count;
+
+ if (!next && data->host_cookie &&
+ data->host_cookie != host->next_data.cookie) {
+ printk(KERN_WARNING "[%s] invalid cookie: data->host_cookie %d"
+ " host->next_data.cookie %d\n",
+ __func__, data->host_cookie, host->next_data.cookie);
+ data->host_cookie = 0;
+ }
+
+ /* Check if next job is already prepared */
+ if (next ||
+ (!next && data->host_cookie != host->next_data.cookie)) {
+ sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg,
+ data->sg_len,
+ (data->flags & MMC_DATA_WRITE) ?
+ DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ } else {
+ sg_count = host->next_data.sg_count;
+ host->next_data.sg_count = 0;
+ }
+
+ if (sg_count == 0)
+ return -EINVAL;
+
+ if (next) {
+ next->sg_count = sg_count;
+ data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie;
+ } else
+ host->sg_count = sg_count;
+
+ return sg_count;
+}
+
static int sdhci_adma_table_pre(struct sdhci_host *host,
struct mmc_data *data)
{
@@ -491,9 +529,8 @@
goto fail;
BUG_ON(host->align_addr & 0x3);
- host->sg_count = dma_map_sg(mmc_dev(host->mmc),
- data->sg, data->sg_len, direction);
- if (host->sg_count == 0)
+ host->sg_count = sdhci_pre_dma_transfer(host, data, NULL);
+ if (host->sg_count < 0)
goto unmap_align;
desc = host->adma_desc;
@@ -638,8 +675,9 @@
}
}
- dma_unmap_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len, direction);
+ if (!data->host_cookie)
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+ direction);
}
static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
@@ -819,11 +857,7 @@
} else {
int sg_cnt;
- sg_cnt = dma_map_sg(mmc_dev(host->mmc),
- data->sg, data->sg_len,
- (data->flags & MMC_DATA_READ) ?
- DMA_FROM_DEVICE :
- DMA_TO_DEVICE);
+ sg_cnt = sdhci_pre_dma_transfer(host, data, NULL);
if (sg_cnt == 0) {
/*
* This only happens when someone fed
@@ -927,9 +961,11 @@
if (host->flags & SDHCI_USE_ADMA)
sdhci_adma_table_post(host, data);
else {
- dma_unmap_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len, (data->flags & MMC_DATA_READ) ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ if (!data->host_cookie)
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg,
+ data->sg_len,
+ (data->flags & MMC_DATA_READ) ?
+ DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
}
@@ -1304,6 +1340,35 @@
return 0;
}
+static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
+ bool is_first_req)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+
+ if (mrq->data->host_cookie) {
+ mrq->data->host_cookie = 0;
+ return;
+ }
+
+ if (host->flags & SDHCI_REQ_USE_DMA)
+ if (sdhci_pre_dma_transfer(host, mrq->data, &host->next_data) < 0)
+ mrq->data->host_cookie = 0;
+}
+
+static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
+ int err)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct mmc_data *data = mrq->data;
+
+ if (host->flags & SDHCI_REQ_USE_DMA) {
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+ (data->flags & MMC_DATA_WRITE) ?
+ DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ data->host_cookie = 0;
+ }
+}
+
static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct sdhci_host *host;
@@ -2016,6 +2081,8 @@
}
static const struct mmc_host_ops sdhci_ops = {
+ .pre_req = sdhci_pre_req,
+ .post_req = sdhci_post_req,
.request = sdhci_request,
.set_ios = sdhci_set_ios,
.get_ro = sdhci_get_ro,
@@ -2598,13 +2665,20 @@
static int sdhci_runtime_pm_get(struct sdhci_host *host)
{
- return pm_runtime_get_sync(host->mmc->parent);
+ if (!mmc_use_core_runtime_pm(host->mmc))
+ return pm_runtime_get_sync(host->mmc->parent);
+ else
+ return 0;
}
static int sdhci_runtime_pm_put(struct sdhci_host *host)
{
- pm_runtime_mark_last_busy(host->mmc->parent);
- return pm_runtime_put_autosuspend(host->mmc->parent);
+ if (!mmc_use_core_runtime_pm(host->mmc)) {
+ pm_runtime_mark_last_busy(host->mmc->parent);
+ return pm_runtime_put_autosuspend(host->mmc->parent);
+ } else {
+ return 0;
+ }
}
int sdhci_runtime_suspend_host(struct sdhci_host *host)
@@ -2805,6 +2879,8 @@
}
}
+ host->next_data.cookie = 1;
+
/*
* If we use DMA, then it's up to the caller to set the DMA
* mask, but PIO does not need the hw shim so we set a new
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 4f96a69..fa84e37 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -538,17 +538,6 @@
ah->WARegVal |= (AR_WA_D3_L1_DISABLE |
AR_WA_ASPM_TIMER_BASED_DISABLE);
- /*
- * Read back AR_WA into a permanent copy and set bits 14 and 17.
- * We need to do this to avoid RMW of this register. We cannot
- * read the reg when chip is asleep.
- */
- ah->WARegVal = REG_READ(ah, AR_WA);
- ah->WARegVal |= (AR_WA_D3_L1_DISABLE |
- AR_WA_ASPM_TIMER_BASED_DISABLE);
-
- ath9k_hw_read_revisions(ah);
-
if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
ath_err(common, "Couldn't reset chip\n");
return -EIO;
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 740f09b..cb00645 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -621,10 +621,8 @@
static void ath9k_init_txpower_limits(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath9k_channel *curchan = ah->curchan;
- ah->txchainmask = common->tx_chainmask;
if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
ath9k_init_band_txpower(sc, IEEE80211_BAND_2GHZ);
if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index 5e66310..77dc327 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -148,31 +148,6 @@
}
}
-static void ath_pci_aspm_init(struct ath_common *common)
-{
- struct ath_softc *sc = (struct ath_softc *) common->priv;
- struct ath_hw *ah = sc->sc_ah;
- struct pci_dev *pdev = to_pci_dev(sc->dev);
- struct pci_dev *parent;
- int pos;
- u8 aspm;
-
- if (!pci_is_pcie(pdev))
- return;
-
- parent = pdev->bus->self;
- if (WARN_ON(!parent))
- return;
-
- pos = pci_pcie_cap(parent);
- pci_read_config_byte(parent, pos + PCI_EXP_LNKCTL, &aspm);
- if (aspm & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) {
- ah->aspm_enabled = true;
- /* Initialize PCIe PM and SERDES registers. */
- ath9k_hw_configpcipowersave(ah, 0, 0);
- }
-}
-
static const struct ath_bus_ops ath_pci_bus_ops = {
.ath_bus_type = ATH_PCI,
.read_cachesize = ath_pci_read_cachesize,
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 0cd9f47..e4d6dc2 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -2527,13 +2527,6 @@
b43_print_fw_helptext(dev->wl, 1);
err = -EOPNOTSUPP;
goto error;
- } else if (fwrev >= 598) {
- b43err(dev->wl, "YOUR FIRMWARE IS TOO NEW. Support for "
- "firmware 598 and up requires kernel 3.2 or newer. You "
- "have to install older firmware or upgrade kernel.\n");
- b43_print_fw_helptext(dev->wl, 1);
- err = -EOPNOTSUPP;
- goto error;
}
dev->fw.rev = fwrev;
dev->fw.patch = fwpatch;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
index 826dd3e..2e1a317 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
@@ -551,9 +551,6 @@
mutex_lock(&priv->mutex);
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- goto out;
-
if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
goto out;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
index 4763426..506b9a0 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
@@ -104,7 +104,7 @@
tx_agc[RF90_PATH_A] = 0x10101010;
tx_agc[RF90_PATH_B] = 0x10101010;
} else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
- TXHIGHPWRLEVEL_LEVEL2) {
+ TXHIGHPWRLEVEL_LEVEL1) {
tx_agc[RF90_PATH_A] = 0x00000000;
tx_agc[RF90_PATH_B] = 0x00000000;
} else{
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 46b4651..88e8d43 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -91,6 +91,16 @@
in the kernel log along with the PMIC option status. The PMIC
type is mapped to a Qualcomm chip part number and logged as well.
+config QPNP_COINCELL
+ tristate "Qualcomm QPNP coincell charger support"
+ depends on SPMI && OF_SPMI
+ help
+ This driver supports the QPNP coincell peripheral found inside of
+ Qualcomm QPNP PMIC devices. The coincell charger provides a means to
+ charge a coincell battery or backup capacitor which is used to
+ maintain PMIC register state when the main battery is removed from the
+ mobile device.
+
config IPA
tristate "IPA support"
depends on SPS
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index 6b9c5ad..efb78e5 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -9,6 +9,7 @@
obj-$(CONFIG_QPNP_POWER_ON) += qpnp-power-on.o
obj-$(CONFIG_QPNP_VIBRATOR) += qpnp-vibrator.o
obj-$(CONFIG_QPNP_CLKDIV) += qpnp-clkdiv.o
+obj-$(CONFIG_QPNP_COINCELL) += qpnp-coincell.o
obj-$(CONFIG_MSM_AVTIMER) += avtimer.o
obj-$(CONFIG_SSM) += ssm.o
obj-$(CONFIG_QPNP_REVID) += qpnp-revid.o
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 1142094..42a0016 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -1919,22 +1919,26 @@
ipa_ctx->aggregation_byte_limit = 1;
ipa_ctx->aggregation_time_limit = 0;
- /* Initialize IPA RM (resource manager) */
- result = ipa_rm_initialize();
- if (result) {
- IPAERR(":cdev_add err=%d\n", -result);
- result = -ENODEV;
- goto fail_ipa_rm_init;
+ if (ipa_ctx->ipa_hw_mode != IPA_HW_MODE_PCIE) {
+ /* Initialize IPA RM (resource manager) */
+ result = ipa_rm_initialize();
+ if (result) {
+ IPAERR(":cdev_add err=%d\n", -result);
+ result = -ENODEV;
+ goto fail_ipa_rm_init;
+ }
}
- a2_mux_init();
+ if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL) {
+ a2_mux_init();
- /* Initialize the tethering bridge driver */
- result = teth_bridge_driver_init();
- if (result) {
- IPAERR(":teth_bridge_driver_init() failed\n");
- result = -ENODEV;
- goto fail_cdev_add;
+ /* Initialize the tethering bridge driver */
+ result = teth_bridge_driver_init();
+ if (result) {
+ IPAERR(":teth_bridge_driver_init() failed\n");
+ result = -ENODEV;
+ goto fail_cdev_add;
+ }
}
/* gate IPA clocks */
diff --git a/drivers/platform/msm/ipa/teth_bridge.c b/drivers/platform/msm/ipa/teth_bridge.c
index 76e2eee..29253cd 100644
--- a/drivers/platform/msm/ipa/teth_bridge.c
+++ b/drivers/platform/msm/ipa/teth_bridge.c
@@ -69,6 +69,11 @@
bool device_mac_addr_known;
};
+struct stats {
+ u64 a2_to_usb_num_sw_tx_packets;
+ u64 usb_to_a2_num_sw_tx_packets;
+};
+
struct teth_bridge_ctx {
struct class *class;
dev_t dev_num;
@@ -90,6 +95,7 @@
struct work_struct comp_hw_bridge_work;
bool comp_hw_bridge_in_progress;
struct teth_aggr_capabilities *aggr_caps;
+ struct stats stats;
};
static struct teth_bridge_ctx *teth_ctx;
@@ -806,6 +812,7 @@
&teth_ctx->mac_addresses.device_mac_addr_known);
/* Send the packet to A2, using a2_service driver API */
+ teth_ctx->stats.usb_to_a2_num_sw_tx_packets++;
res = a2_mux_write(A2_MUX_TETHERED_0, skb);
if (res) {
TETH_ERR("Packet send failure, dropping packet !\n");
@@ -843,6 +850,7 @@
mac_addresses.host_pc_mac_addr_known);
/* Send the packet to USB */
+ teth_ctx->stats.a2_to_usb_num_sw_tx_packets++;
res = ipa_tx_dp(IPA_CLIENT_USB_CONS, skb, NULL);
if (res) {
TETH_ERR("Packet send failure, dropping packet !\n");
@@ -1216,6 +1224,8 @@
static struct dentry *dfile_link_protocol;
static struct dentry *dfile_get_aggr_params;
static struct dentry *dfile_set_aggr_protocol;
+static struct dentry *dfile_stats;
+static struct dentry *dfile_is_hw_bridge_complete;
static ssize_t teth_debugfs_read_link_protocol(struct file *file,
char __user *ubuf,
@@ -1351,6 +1361,43 @@
return count;
}
+static ssize_t teth_debugfs_stats(struct file *file,
+ char __user *ubuf,
+ size_t count,
+ loff_t *ppos)
+{
+ int nbytes = 0;
+
+ nbytes += scnprintf(&dbg_buff[nbytes],
+ TETH_MAX_MSG_LEN - nbytes,
+ "USB to A2 SW Tx packets: %lld\n",
+ teth_ctx->stats.usb_to_a2_num_sw_tx_packets);
+ nbytes += scnprintf(&dbg_buff[nbytes],
+ TETH_MAX_MSG_LEN - nbytes,
+ "A2 to USB SW Tx packets: %lld\n",
+ teth_ctx->stats.a2_to_usb_num_sw_tx_packets);
+ return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
+}
+
+static ssize_t teth_debugfs_hw_bridge_status(struct file *file,
+ char __user *ubuf,
+ size_t count,
+ loff_t *ppos)
+{
+ int nbytes = 0;
+
+ if (teth_ctx->is_hw_bridge_complete)
+ nbytes += scnprintf(&dbg_buff[nbytes],
+ TETH_MAX_MSG_LEN - nbytes,
+ "HW bridge is in use.\n");
+ else
+ nbytes += scnprintf(&dbg_buff[nbytes],
+ TETH_MAX_MSG_LEN - nbytes,
+ "SW bridge is in use. HW bridge not complete yet.\n");
+
+ return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
+}
+
const struct file_operations teth_link_protocol_ops = {
.read = teth_debugfs_read_link_protocol,
.write = teth_debugfs_write_link_protocol,
@@ -1364,6 +1411,14 @@
.write = teth_debugfs_set_aggr_protocol,
};
+const struct file_operations teth_stats_ops = {
+ .read = teth_debugfs_stats,
+};
+
+const struct file_operations teth_hw_bridge_status_ops = {
+ .read = teth_debugfs_hw_bridge_status,
+};
+
void teth_debugfs_init(void)
{
const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH;
@@ -1400,6 +1455,23 @@
goto fail;
}
+ dfile_stats =
+ debugfs_create_file("stats", read_only_mode, dent,
+ 0, &teth_stats_ops);
+ if (!dfile_stats || IS_ERR(dfile_stats)) {
+ IPAERR("fail to create file stats\n");
+ goto fail;
+ }
+
+ dfile_is_hw_bridge_complete =
+ debugfs_create_file("is_hw_bridge_complete", read_only_mode,
+ dent, 0, &teth_hw_bridge_status_ops);
+ if (!dfile_is_hw_bridge_complete ||
+ IS_ERR(dfile_is_hw_bridge_complete)) {
+ IPAERR("fail to create file is_hw_bridge_complete\n");
+ goto fail;
+ }
+
return;
fail:
debugfs_remove_recursive(dent);
diff --git a/drivers/platform/msm/qpnp-coincell.c b/drivers/platform/msm/qpnp-coincell.c
new file mode 100644
index 0000000..e08fd7d
--- /dev/null
+++ b/drivers/platform/msm/qpnp-coincell.c
@@ -0,0 +1,266 @@
+/* Copyright (c) 2013, 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/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#define QPNP_COINCELL_DRIVER_NAME "qcom,qpnp-coincell"
+
+struct qpnp_coincell {
+ struct spmi_device *spmi_dev;
+ u16 base_addr;
+};
+
+#define QPNP_COINCELL_REG_TYPE 0x04
+#define QPNP_COINCELL_REG_SUBTYPE 0x05
+#define QPNP_COINCELL_REG_RSET 0x44
+#define QPNP_COINCELL_REG_VSET 0x45
+#define QPNP_COINCELL_REG_ENABLE 0x46
+
+#define QPNP_COINCELL_TYPE 0x02
+#define QPNP_COINCELL_SUBTYPE 0x20
+#define QPNP_COINCELL_ENABLE 0x80
+#define QPNP_COINCELL_DISABLE 0x00
+
+static const int qpnp_rset_map[] = {2100, 1700, 1200, 800};
+static const int qpnp_vset_map[] = {2500, 3200, 3100, 3000};
+
+static int qpnp_coincell_set_resistance(struct qpnp_coincell *chip, int rset)
+{
+ int i, rc;
+ u8 reg;
+
+ for (i = 0; i < ARRAY_SIZE(qpnp_rset_map); i++)
+ if (rset == qpnp_rset_map[i])
+ break;
+
+ if (i >= ARRAY_SIZE(qpnp_rset_map)) {
+ pr_err("invalid rset=%d value\n", rset);
+ return -EINVAL;
+ }
+
+ reg = i;
+ rc = spmi_ext_register_writel(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
+ chip->base_addr + QPNP_COINCELL_REG_RSET, ®, 1);
+ if (rc)
+ dev_err(&chip->spmi_dev->dev, "%s: could not write to RSET register, rc=%d\n",
+ __func__, rc);
+
+ return rc;
+}
+
+static int qpnp_coincell_set_voltage(struct qpnp_coincell *chip, int vset)
+{
+ int i, rc;
+ u8 reg;
+
+ for (i = 0; i < ARRAY_SIZE(qpnp_vset_map); i++)
+ if (vset == qpnp_vset_map[i])
+ break;
+
+ if (i >= ARRAY_SIZE(qpnp_vset_map)) {
+ pr_err("invalid vset=%d value\n", vset);
+ return -EINVAL;
+ }
+
+ reg = i;
+ rc = spmi_ext_register_writel(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
+ chip->base_addr + QPNP_COINCELL_REG_VSET, ®, 1);
+ if (rc)
+ dev_err(&chip->spmi_dev->dev, "%s: could not write to VSET register, rc=%d\n",
+ __func__, rc);
+
+ return rc;
+}
+
+static int qpnp_coincell_set_charge(struct qpnp_coincell *chip, bool enabled)
+{
+ int rc;
+ u8 reg;
+
+ reg = enabled ? QPNP_COINCELL_ENABLE : QPNP_COINCELL_DISABLE;
+ rc = spmi_ext_register_writel(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
+ chip->base_addr + QPNP_COINCELL_REG_ENABLE, ®, 1);
+ if (rc)
+ dev_err(&chip->spmi_dev->dev, "%s: could not write to ENABLE register, rc=%d\n",
+ __func__, rc);
+
+ return rc;
+}
+
+static void qpnp_coincell_charger_show_state(struct qpnp_coincell *chip)
+{
+ int rc, rset, vset, temp;
+ bool enabled;
+ u8 reg[QPNP_COINCELL_REG_ENABLE - QPNP_COINCELL_REG_RSET + 1];
+
+ rc = spmi_ext_register_readl(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
+ chip->base_addr + QPNP_COINCELL_REG_RSET, reg, ARRAY_SIZE(reg));
+ if (rc) {
+ dev_err(&chip->spmi_dev->dev, "%s: could not read RSET register, rc=%d\n",
+ __func__, rc);
+ return;
+ }
+
+ temp = reg[QPNP_COINCELL_REG_RSET - QPNP_COINCELL_REG_RSET];
+ if (temp >= ARRAY_SIZE(qpnp_rset_map)) {
+ dev_err(&chip->spmi_dev->dev, "unknown RSET=0x%02X register value\n",
+ temp);
+ return;
+ }
+ rset = qpnp_rset_map[temp];
+
+ temp = reg[QPNP_COINCELL_REG_VSET - QPNP_COINCELL_REG_RSET];
+ if (temp >= ARRAY_SIZE(qpnp_vset_map)) {
+ dev_err(&chip->spmi_dev->dev, "unknown VSET=0x%02X register value\n",
+ temp);
+ return;
+ }
+ vset = qpnp_vset_map[temp];
+
+ temp = reg[QPNP_COINCELL_REG_ENABLE - QPNP_COINCELL_REG_RSET];
+ enabled = temp & QPNP_COINCELL_ENABLE;
+
+ pr_info("enabled=%c, voltage=%d mV, resistance=%d ohm\n",
+ (enabled ? 'Y' : 'N'), vset, rset);
+}
+
+static int qpnp_coincell_check_type(struct qpnp_coincell *chip)
+{
+ int rc;
+ u8 type[2];
+
+ rc = spmi_ext_register_readl(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
+ chip->base_addr + QPNP_COINCELL_REG_TYPE, type, 2);
+ if (rc) {
+ dev_err(&chip->spmi_dev->dev, "%s: could not read type register, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ if (type[0] != QPNP_COINCELL_TYPE || type[1] != QPNP_COINCELL_SUBTYPE) {
+ dev_err(&chip->spmi_dev->dev, "%s: invalid type=0x%02X or subtype=0x%02X register value\n",
+ __func__, type[0], type[1]);
+ return -ENODEV;
+ }
+
+ return rc;
+}
+
+static int qpnp_coincell_probe(struct spmi_device *spmi)
+{
+ struct device_node *node = spmi->dev.of_node;
+ struct qpnp_coincell *chip;
+ struct resource *res;
+ u32 temp;
+ int rc = 0;
+
+ if (!node) {
+ dev_err(&spmi->dev, "%s: device node missing\n", __func__);
+ return -ENODEV;
+ }
+
+ chip = devm_kzalloc(&spmi->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip) {
+ dev_err(&spmi->dev, "%s: cannot allocate qpnp_coincell\n",
+ __func__);
+ return -ENOMEM;
+ }
+ chip->spmi_dev = spmi;
+
+ res = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&spmi->dev, "%s: node is missing base address\n",
+ __func__);
+ return -EINVAL;
+ }
+ chip->base_addr = res->start;
+
+ rc = qpnp_coincell_check_type(chip);
+ if (rc)
+ return rc;
+
+ rc = of_property_read_u32(node, "qcom,rset-ohms", &temp);
+ if (!rc) {
+ rc = qpnp_coincell_set_resistance(chip, temp);
+ if (rc)
+ return rc;
+ }
+
+ rc = of_property_read_u32(node, "qcom,vset-millivolts", &temp);
+ if (!rc) {
+ rc = qpnp_coincell_set_voltage(chip, temp);
+ if (rc)
+ return rc;
+ }
+
+ rc = of_property_read_u32(node, "qcom,charge-enable", &temp);
+ if (!rc) {
+ rc = qpnp_coincell_set_charge(chip, temp);
+ if (rc)
+ return rc;
+ }
+
+ qpnp_coincell_charger_show_state(chip);
+
+ return 0;
+}
+
+static int __devexit qpnp_coincell_remove(struct spmi_device *spmi)
+{
+ return 0;
+}
+
+static struct of_device_id qpnp_coincell_match_table[] = {
+ { .compatible = QPNP_COINCELL_DRIVER_NAME, },
+ {}
+};
+
+static const struct spmi_device_id qpnp_coincell_id[] = {
+ { QPNP_COINCELL_DRIVER_NAME, 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(spmi, qpnp_coincell_id);
+
+static struct spmi_driver qpnp_coincell_driver = {
+ .driver = {
+ .name = QPNP_COINCELL_DRIVER_NAME,
+ .of_match_table = qpnp_coincell_match_table,
+ .owner = THIS_MODULE,
+ },
+ .probe = qpnp_coincell_probe,
+ .remove = __devexit_p(qpnp_coincell_remove),
+ .id_table = qpnp_coincell_id,
+};
+
+static int __init qpnp_coincell_init(void)
+{
+ return spmi_driver_register(&qpnp_coincell_driver);
+}
+
+static void __exit qpnp_coincell_exit(void)
+{
+ spmi_driver_unregister(&qpnp_coincell_driver);
+}
+
+MODULE_DESCRIPTION("QPNP PMIC coincell charger driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(qpnp_coincell_init);
+module_exit(qpnp_coincell_exit);
diff --git a/drivers/platform/msm/ssm.c b/drivers/platform/msm/ssm.c
index c57bb91..3afb954 100644
--- a/drivers/platform/msm/ssm.c
+++ b/drivers/platform/msm/ssm.c
@@ -66,7 +66,7 @@
struct device *dev;
smd_channel_t *ch;
ion_phys_addr_t buff_phys;
- ion_virt_addr_t buff_virt;
+ void *buff_virt;
dev_t ssm_device_no;
struct work_struct ipc_work;
struct mutex mutex;
@@ -401,7 +401,7 @@
const struct elf32_phdr *phdr;
struct ion_handle *ion_handle;
ion_phys_addr_t buff_phys;
- ion_virt_addr_t buff_virt;
+ void *buff_virt;
/* Check if TZ app already loaded */
app_req.cmd_id = APP_LOOKUP_COMMAND;
@@ -509,8 +509,7 @@
goto ion_free;
}
- buff_virt =
- (ion_virt_addr_t)ion_map_kernel(ssm_drv->ssm_ion_client,
+ buff_virt = ion_map_kernel(ssm_drv->ssm_ion_client,
ion_handle);
if (IS_ERR_OR_NULL((void *)buff_virt)) {
rc = PTR_ERR((void *)buff_virt);
@@ -605,8 +604,7 @@
goto ion_free;
}
- ssm->buff_virt =
- (ion_virt_addr_t)ion_map_kernel(ssm->ssm_ion_client,
+ ssm->buff_virt = ion_map_kernel(ssm->ssm_ion_client,
ssm->ssm_ion_handle);
if (IS_ERR_OR_NULL((void *)ssm->buff_virt)) {
rc = PTR_ERR((void *)ssm->buff_virt);
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index bc2e2ae..0d161b7 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -432,6 +432,7 @@
tristate "QPNP Charger driver"
depends on SPMI
depends on OF_SPMI
+ depends on THERMAL_QPNP_ADC_TM
help
Say Y here to enable the switch mode battery charger
and boost device which supports USB detection and charging. The driver
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 7833afa..3d9e4b7 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -171,17 +171,27 @@
* @boost_base: boost peripheral base address
* @misc_base: misc peripheral base address
* @freq_base: freq peripheral base address
+ * @bat_is_cool: indicates that battery is cool
+ * @bat_is_warm: indicates that battery is warm
* @chg_done: indicates that charging is completed
* @usb_present: present status of usb
* @dc_present: present status of dc
+ * @batt_present: present status of battery
* @use_default_batt_values: flag to report default battery properties
* @max_voltage_mv: the max volts the batt should be charged up to
* @min_voltage_mv: min battery voltage before turning the FET on
- * @resume_voltage_mv: voltage at which the battery resumes charging
+ * @max_bat_chg_current: maximum battery charge current in mA
+ * @warm_bat_chg_ma: warm battery maximum charge current in mA
+ * @cool_bat_chg_ma: cool battery maximum charge current in mA
+ * @warm_bat_mv: warm temperature battery target voltage
+ * @cool_bat_mv: cool temperature battery target voltage
+ * @resume_delta_mv: voltage delta at which battery resumes charging
* @term_current: the charging based term current
* @safe_current: battery safety current setting
* @maxinput_usb_ma: Maximum Input current USB
* @maxinput_dc_ma: Maximum Input current DC
+ * @warm_bat_degc Warm battery temperature in degree Celsius
+ * @cool_bat_degc Cool battery temperature in degree Celsius
* @revision: PMIC revision
* @thermal_levels amount of thermal mitigation levels
* @thermal_mitigation thermal mitigation level values
@@ -208,20 +218,32 @@
unsigned int usbin_valid_irq;
unsigned int dcin_valid_irq;
unsigned int chg_done_irq;
+ unsigned int chg_fastchg_irq;
+ unsigned int chg_trklchg_irq;
unsigned int chg_failed_irq;
+ unsigned int batt_pres_irq;
+ bool bat_is_cool;
+ bool bat_is_warm;
bool chg_done;
bool usb_present;
bool dc_present;
+ bool batt_present;
bool charging_disabled;
bool use_default_batt_values;
unsigned int max_bat_chg_current;
+ unsigned int warm_bat_chg_ma;
+ unsigned int cool_bat_chg_ma;
unsigned int safe_voltage_mv;
unsigned int max_voltage_mv;
unsigned int min_voltage_mv;
- unsigned int resume_voltage_mv;
+ unsigned int warm_bat_mv;
+ unsigned int cool_bat_mv;
+ unsigned int resume_delta_mv;
unsigned int term_current;
unsigned int maxinput_usb_ma;
unsigned int maxinput_dc_ma;
+ unsigned int warm_bat_degc;
+ unsigned int cool_bat_degc;
unsigned int safe_current;
unsigned int revision;
unsigned int thermal_levels;
@@ -232,6 +254,7 @@
struct power_supply *bms_psy;
struct power_supply batt_psy;
uint32_t flags;
+ struct qpnp_adc_tm_btm_param adc_param;
};
static struct of_device_id qpnp_charger_match_table[] = {
@@ -323,6 +346,23 @@
return (usb_otg_en & USB_OTG_EN_BIT) ? 1 : 0;
}
+static int
+qpnp_chg_is_batt_present(struct qpnp_chg_chip *chip)
+{
+ u8 batt_pres_rt_sts;
+ int rc;
+
+ rc = qpnp_chg_read(chip, &batt_pres_rt_sts,
+ INT_RT_STS(chip->bat_if_base), 1);
+ if (rc) {
+ pr_err("spmi read failed: addr=%03X, rc=%d\n",
+ INT_RT_STS(chip->bat_if_base), rc);
+ return rc;
+ }
+
+ return (batt_pres_rt_sts & BATT_PRES_IRQ) ? 1 : 0;
+}
+
#define USB_VALID_BIT BIT(7)
static int
qpnp_chg_is_usb_chg_plugged_in(struct qpnp_chg_chip *chip)
@@ -493,6 +533,23 @@
}
static irqreturn_t
+qpnp_chg_bat_if_batt_pres_irq_handler(int irq, void *_chip)
+{
+ struct qpnp_chg_chip *chip = _chip;
+ int batt_present;
+
+ batt_present = qpnp_chg_is_batt_present(chip);
+ pr_debug("batt-pres triggered: %d\n", batt_present);
+
+ if (chip->batt_present ^ batt_present) {
+ chip->batt_present = batt_present;
+ power_supply_changed(&chip->batt_psy);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
qpnp_chg_dc_dcin_valid_irq_handler(int irq, void *_chip)
{
struct qpnp_chg_chip *chip = _chip;
@@ -527,12 +584,47 @@
}
static irqreturn_t
-qpnp_chg_chgr_chg_done_irq_handler(int irq, void *_chip)
+qpnp_chg_chgr_chg_trklchg_irq_handler(int irq, void *_chip)
{
struct qpnp_chg_chip *chip = _chip;
+ pr_debug("TRKL IRQ triggered\n");
+
+ chip->chg_done = false;
+ power_supply_changed(&chip->batt_psy);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+qpnp_chg_chgr_chg_fastchg_irq_handler(int irq, void *_chip)
+{
+ struct qpnp_chg_chip *chip = _chip;
+
+ pr_debug("FAST_CHG IRQ triggered\n");
+
+ chip->chg_done = false;
+ power_supply_changed(&chip->batt_psy);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+qpnp_chg_chgr_chg_done_irq_handler(int irq, void *_chip)
+{
+ struct qpnp_chg_chip *chip = _chip;
+ u8 chgr_sts;
+ int rc;
+
pr_debug("CHG_DONE IRQ triggered\n");
+
+ rc = qpnp_chg_read(chip, &chgr_sts,
+ INT_RT_STS(chip->chgr_base), 1);
+ if (rc)
+ pr_err("failed to read interrupt sts %d\n", rc);
+
chip->chg_done = true;
+ power_supply_changed(&chip->batt_psy);
return IRQ_HANDLED;
}
@@ -597,8 +689,8 @@
return rc;
}
-static
-int switch_usb_to_charge_mode(struct qpnp_chg_chip *chip)
+static int
+switch_usb_to_charge_mode(struct qpnp_chg_chip *chip)
{
int rc;
@@ -625,8 +717,8 @@
return 0;
}
-static
-int switch_usb_to_host_mode(struct qpnp_chg_chip *chip)
+static int
+switch_usb_to_host_mode(struct qpnp_chg_chip *chip)
{
int rc;
@@ -791,19 +883,16 @@
int rc;
u8 chgr_sts;
+ if (chip->chg_done)
+ return POWER_SUPPLY_STATUS_FULL;
+
rc = qpnp_chg_read(chip, &chgr_sts,
INT_RT_STS(chip->chgr_base), 1);
if (rc) {
pr_err("failed to read interrupt sts %d\n", rc);
- return POWER_SUPPLY_STATUS_DISCHARGING;
+ return POWER_SUPPLY_CHARGE_TYPE_NONE;
}
- pr_debug("chgr sts 0x%x\n", chgr_sts);
- if (chgr_sts & CHG_DONE_IRQ || chip->chg_done)
- return POWER_SUPPLY_STATUS_FULL;
- else
- chip->chg_done = false;
-
if (chgr_sts & TRKL_CHG_ON_IRQ)
return POWER_SUPPLY_STATUS_CHARGING;
if (chgr_sts & FAST_CHG_ON_IRQ)
@@ -1147,8 +1236,33 @@
temp = (voltage - QPNP_CHG_V_MIN_MV) / QPNP_CHG_V_STEP_MV;
pr_debug("voltage=%d setting %02x\n", voltage, temp);
- return qpnp_chg_write(chip, &temp,
- chip->chgr_base + CHGR_VDD_MAX, 1);
+ return qpnp_chg_write(chip, &temp, chip->chgr_base + CHGR_VDD_MAX, 1);
+}
+
+/* JEITA compliance logic */
+static void
+qpnp_chg_set_appropriate_vddmax(struct qpnp_chg_chip *chip)
+{
+ if (chip->bat_is_cool)
+ qpnp_chg_vddmax_set(chip, chip->cool_bat_mv);
+ else if (chip->bat_is_warm)
+ qpnp_chg_vddmax_set(chip, chip->warm_bat_mv);
+ else
+ qpnp_chg_vddmax_set(chip, chip->max_voltage_mv);
+}
+
+static void
+qpnp_chg_set_appropriate_vbatdet(struct qpnp_chg_chip *chip)
+{
+ if (chip->bat_is_cool)
+ qpnp_chg_vbatdet_set(chip, chip->cool_bat_mv
+ - chip->resume_delta_mv);
+ else if (chip->bat_is_warm)
+ qpnp_chg_vbatdet_set(chip, chip->warm_bat_mv
+ - chip->resume_delta_mv);
+ else
+ qpnp_chg_vbatdet_set(chip, chip->max_voltage_mv
+ - chip->resume_delta_mv);
}
static void
@@ -1156,6 +1270,12 @@
{
unsigned int chg_current = chip->max_bat_chg_current;
+ if (chip->bat_is_cool)
+ chg_current = min(chg_current, chip->cool_bat_chg_ma);
+
+ if (chip->bat_is_warm)
+ chg_current = min(chg_current, chip->warm_bat_chg_ma);
+
if (chip->therm_lvl_sel != 0 && chip->thermal_mitigation)
chg_current = min(chg_current,
chip->thermal_mitigation[chip->therm_lvl_sel]);
@@ -1181,6 +1301,58 @@
}
}
+#define TEMP_HYSTERISIS_DEGC 2
+static void
+qpnp_chg_adc_notification(enum qpnp_tm_state state, void *ctx)
+{
+ struct qpnp_chg_chip *chip = ctx;
+ bool bat_warm = 0, bat_cool = 0;
+
+ if (state >= ADC_TM_STATE_NUM) {
+ pr_err("invalid notification %d\n", state);
+ return;
+ }
+
+ pr_debug("state = %s\n", state == ADC_TM_HIGH_STATE ? "high" : "low");
+
+ if (state == ADC_TM_HIGH_STATE) {
+ if (!chip->bat_is_warm) {
+ bat_warm = true;
+ bat_cool = false;
+ chip->adc_param.low_temp =
+ chip->warm_bat_degc - TEMP_HYSTERISIS_DEGC;
+ } else if (chip->bat_is_cool) {
+ bat_warm = false;
+ bat_cool = false;
+ chip->adc_param.high_temp = chip->warm_bat_degc;
+ }
+ } else {
+ if (!chip->bat_is_cool) {
+ bat_cool = true;
+ bat_warm = false;
+ chip->adc_param.high_temp =
+ chip->cool_bat_degc + TEMP_HYSTERISIS_DEGC;
+ } else if (chip->bat_is_warm) {
+ bat_cool = false;
+ bat_warm = false;
+ chip->adc_param.low_temp = chip->cool_bat_degc;
+ }
+ }
+
+ if (chip->bat_is_cool ^ bat_cool || chip->bat_is_warm ^ bat_warm) {
+ /* set appropriate voltages and currents */
+ qpnp_chg_set_appropriate_vddmax(chip);
+ qpnp_chg_set_appropriate_battery_current(chip);
+ qpnp_chg_set_appropriate_vbatdet(chip);
+
+ chip->bat_is_cool = bat_cool;
+ chip->bat_is_warm = bat_warm;
+ }
+
+ /* re-arm ADC interrupt */
+ qpnp_adc_tm_btm_configure(&chip->adc_param);
+}
+
static int
qpnp_batt_power_set_property(struct power_supply *psy,
enum power_supply_property psp,
@@ -1231,20 +1403,37 @@
return -ENXIO;
}
+ chip->chg_fastchg_irq = spmi_get_irq_byname(chip->spmi,
+ spmi_resource, "fast-chg-on");
+ if (chip->chg_fastchg_irq < 0) {
+ pr_err("Unable to get fast-chg-on irq\n");
+ return -ENXIO;
+ }
+
+ chip->chg_trklchg_irq = spmi_get_irq_byname(chip->spmi,
+ spmi_resource, "trkl-chg-on");
+ if (chip->chg_trklchg_irq < 0) {
+ pr_err("Unable to get trkl-chg-on irq\n");
+ return -ENXIO;
+ }
+
chip->chg_failed_irq = spmi_get_irq_byname(chip->spmi,
spmi_resource, "chg-failed");
if (chip->chg_failed_irq < 0) {
pr_err("Unable to get chg_failed irq\n");
return -ENXIO;
}
+
rc |= devm_request_irq(chip->dev, chip->chg_done_irq,
qpnp_chg_chgr_chg_done_irq_handler,
- IRQF_TRIGGER_RISING, "chg_done", chip);
+ IRQF_TRIGGER_RISING,
+ "chg_done", chip);
if (rc < 0) {
pr_err("Can't request %d chg_done for chg: %d\n",
chip->chg_done_irq, rc);
return -ENXIO;
}
+
rc |= devm_request_irq(chip->dev, chip->chg_failed_irq,
qpnp_chg_chgr_chg_failed_irq_handler,
IRQF_TRIGGER_RISING, "chg_failed", chip);
@@ -1254,6 +1443,26 @@
return -ENXIO;
}
+ rc |= devm_request_irq(chip->dev, chip->chg_fastchg_irq,
+ qpnp_chg_chgr_chg_fastchg_irq_handler,
+ IRQF_TRIGGER_RISING,
+ "fast-chg-on", chip);
+ if (rc < 0) {
+ pr_err("Can't request %d fast-chg-on for chg: %d\n",
+ chip->chg_fastchg_irq, rc);
+ return -ENXIO;
+ }
+
+ rc |= devm_request_irq(chip->dev, chip->chg_trklchg_irq,
+ qpnp_chg_chgr_chg_trklchg_irq_handler,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "fast-chg-on", chip);
+ if (rc < 0) {
+ pr_err("Can't request %d trkl-chg-on for chg: %d\n",
+ chip->chg_trklchg_irq, rc);
+ return -ENXIO;
+ }
+
rc = qpnp_chg_vinmin_set(chip, chip->min_voltage_mv);
if (rc) {
pr_debug("failed setting min_voltage rc=%d\n", rc);
@@ -1269,7 +1478,8 @@
pr_debug("failed setting safe_voltage rc=%d\n", rc);
return rc;
}
- rc = qpnp_chg_vbatdet_set(chip, chip->resume_voltage_mv);
+ rc = qpnp_chg_vbatdet_set(chip,
+ chip->max_voltage_mv - chip->resume_delta_mv);
if (rc) {
pr_debug("failed setting resume_voltage rc=%d\n", rc);
return rc;
@@ -1279,10 +1489,12 @@
pr_debug("failed setting ibatmax rc=%d\n", rc);
return rc;
}
- rc = qpnp_chg_ibatterm_set(chip, chip->term_current);
- if (rc) {
- pr_debug("failed setting ibatterm rc=%d\n", rc);
- return rc;
+ if (chip->term_current) {
+ rc = qpnp_chg_ibatterm_set(chip, chip->term_current);
+ if (rc) {
+ pr_debug("failed setting ibatterm rc=%d\n", rc);
+ return rc;
+ }
}
rc = qpnp_chg_ibatsafe_set(chip, chip->safe_current);
if (rc) {
@@ -1293,11 +1505,14 @@
rc = qpnp_chg_masked_write(chip, chip->chgr_base + 0x62,
0xFF, 0xA0, 1);
- /* HACK: use analog EOC */
+ /* HACK: use digital EOC */
rc = qpnp_chg_masked_write(chip, chip->chgr_base +
CHGR_IBAT_TERM_CHGR,
- 0x80, 0x80, 1);
+ 0x88, 0x80, 1);
+ enable_irq_wake(chip->chg_fastchg_irq);
+ enable_irq_wake(chip->chg_trklchg_irq);
+ enable_irq_wake(chip->chg_failed_irq);
enable_irq_wake(chip->chg_done_irq);
break;
case SMBB_BUCK_SUBTYPE:
@@ -1313,6 +1528,23 @@
break;
case SMBB_BAT_IF_SUBTYPE:
case SMBBP_BAT_IF_SUBTYPE:
+ chip->batt_pres_irq = spmi_get_irq_byname(chip->spmi,
+ spmi_resource, "batt-pres");
+ if (chip->batt_pres_irq < 0) {
+ pr_err("Unable to get batt-pres irq\n");
+ return -ENXIO;
+ }
+ rc = devm_request_irq(chip->dev, chip->batt_pres_irq,
+ qpnp_chg_bat_if_batt_pres_irq_handler,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "bat_if_batt_pres", chip);
+ if (rc < 0) {
+ pr_err("Can't request %d batt-pres irq for chg: %d\n",
+ chip->batt_pres_irq, rc);
+ return -ENXIO;
+ }
+
+ enable_irq_wake(chip->batt_pres_irq);
break;
case SMBB_USB_CHGPTH_SUBTYPE:
case SMBBP_USB_CHGPTH_SUBTYPE:
@@ -1427,7 +1659,7 @@
/* Get the vddmax property */
rc = of_property_read_u32(spmi->dev.of_node, "qcom,chg-vddmax-mv",
&chip->max_voltage_mv);
- if (rc && rc != -EINVAL) {
+ if (rc) {
pr_err("Error reading vddmax property %d\n", rc);
goto fail_chg_enable;
}
@@ -1435,7 +1667,7 @@
/* Get the vinmin property */
rc = of_property_read_u32(spmi->dev.of_node, "qcom,chg-vinmin-mv",
&chip->min_voltage_mv);
- if (rc && rc != -EINVAL) {
+ if (rc) {
pr_err("Error reading vddmax property %d\n", rc);
goto fail_chg_enable;
}
@@ -1443,17 +1675,17 @@
/* Get the vddmax property */
rc = of_property_read_u32(spmi->dev.of_node, "qcom,chg-vddsafe-mv",
&chip->safe_voltage_mv);
- if (rc && rc != -EINVAL) {
+ if (rc) {
pr_err("Error reading vddsave property %d\n", rc);
goto fail_chg_enable;
}
- /* Get the ibatsafe property */
+ /* Get the vbatdet-delta property */
rc = of_property_read_u32(spmi->dev.of_node,
- "qcom,chg-vbatdet-mv",
- &chip->resume_voltage_mv);
- if (rc) {
- pr_err("Error reading vbatdet property %d\n", rc);
+ "qcom,chg-vbatdet-delta-mv",
+ &chip->resume_delta_mv);
+ if (rc && rc != -EINVAL) {
+ pr_err("Error reading vbatdet-delta property %d\n", rc);
goto fail_chg_enable;
}
@@ -1478,17 +1710,8 @@
/* Get the ibatmax property */
rc = of_property_read_u32(spmi->dev.of_node, "qcom,chg-ibatmax-ma",
&chip->max_bat_chg_current);
- if (rc && rc != -EINVAL) {
- pr_err("Error reading ibatmax property %d\n", rc);
- goto fail_chg_enable;
- }
-
- /* Get the ibatsafe property */
- rc = of_property_read_u32(spmi->dev.of_node,
- "qcom,chg-vbatdet-mv",
- &chip->resume_voltage_mv);
if (rc) {
- pr_err("Error reading vbatdet property %d\n", rc);
+ pr_err("Error reading ibatmax property %d\n", rc);
goto fail_chg_enable;
}
@@ -1514,6 +1737,67 @@
chip->charging_disabled = of_property_read_bool(spmi->dev.of_node,
"qcom,chg-charging-disabled");
+ /* Get the warm-bat-degc property */
+ rc = of_property_read_u32(spmi->dev.of_node,
+ "qcom,chg-warm-bat-degc",
+ &chip->warm_bat_degc);
+ if (rc && rc != -EINVAL) {
+ pr_err("Error reading warm-bat-degc property %d\n", rc);
+ goto fail_chg_enable;
+ }
+
+ /* Get the cool-bat-degc property */
+ rc = of_property_read_u32(spmi->dev.of_node,
+ "qcom,chg-cool-bat-degc",
+ &chip->cool_bat_degc);
+ if (rc && rc != -EINVAL) {
+ pr_err("Error reading cool-bat-degc property %d\n", rc);
+ goto fail_chg_enable;
+ }
+
+ if (chip->cool_bat_degc && chip->warm_bat_degc) {
+ rc = qpnp_adc_tm_is_ready();
+ if (rc) {
+ pr_err("tm not ready %d\n", rc);
+ goto fail_chg_enable;
+ }
+
+ /* Get the ibatmax-warm property */
+ rc = of_property_read_u32(spmi->dev.of_node,
+ "qcom,chg-ibatmax-warm-ma",
+ &chip->warm_bat_chg_ma);
+ if (rc) {
+ pr_err("Error reading ibatmax-warm-ma %d\n", rc);
+ goto fail_chg_enable;
+ }
+
+ /* Get the ibatmax-cool property */
+ rc = of_property_read_u32(spmi->dev.of_node,
+ "qcom,chg-ibatmax-cool-ma",
+ &chip->cool_bat_chg_ma);
+ if (rc) {
+ pr_err("Error reading ibatmax-cool-ma %d\n", rc);
+ goto fail_chg_enable;
+ }
+ /* Get the cool-bat-mv property */
+ rc = of_property_read_u32(spmi->dev.of_node,
+ "qcom,chg-cool-bat-mv",
+ &chip->cool_bat_mv);
+ if (rc) {
+ pr_err("Error reading cool-bat-mv property %d\n", rc);
+ goto fail_chg_enable;
+ }
+
+ /* Get the warm-bat-mv property */
+ rc = of_property_read_u32(spmi->dev.of_node,
+ "qcom,chg-warm-bat-mv",
+ &chip->warm_bat_mv);
+ if (rc) {
+ pr_err("Error reading warm-bat-mv property %d\n", rc);
+ goto fail_chg_enable;
+ }
+ }
+
/* Get the fake-batt-values property */
chip->use_default_batt_values = of_property_read_bool(spmi->dev.of_node,
"qcom,chg-use-default-batt-values");
@@ -1701,6 +1985,22 @@
}
}
+ if (chip->cool_bat_degc && chip->warm_bat_degc) {
+ chip->adc_param.low_temp = chip->cool_bat_degc;
+ chip->adc_param.high_temp = chip->warm_bat_degc;
+ chip->adc_param.timer_interval = ADC_MEAS2_INTERVAL_1S;
+ chip->adc_param.state_request = ADC_TM_HIGH_LOW_THR_ENABLE;
+ chip->adc_param.btm_ctx = chip;
+ chip->adc_param.threshold_notification =
+ qpnp_chg_adc_notification;
+
+ rc = qpnp_adc_tm_btm_configure(&chip->adc_param);
+ if (rc) {
+ pr_err("request ADC error %d\n", rc);
+ goto fail_chg_enable;
+ }
+ }
+
qpnp_chg_charge_en(chip, !chip->charging_disabled);
qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c
index aea91ef..8097e69 100644
--- a/drivers/rtc/rtc-pm8xxx.c
+++ b/drivers/rtc/rtc-pm8xxx.c
@@ -15,31 +15,37 @@
#include <linux/rtc.h>
#include <linux/pm.h>
#include <linux/slab.h>
-#include<linux/spinlock.h>
+#include <linux/spinlock.h>
#include <linux/mfd/pm8xxx/core.h>
#include <linux/mfd/pm8xxx/rtc.h>
/* RTC Register offsets from RTC CTRL REG */
-#define PM8XXX_ALARM_CTRL_OFFSET 0x01
-#define PM8XXX_RTC_WRITE_OFFSET 0x02
-#define PM8XXX_RTC_READ_OFFSET 0x06
-#define PM8XXX_ALARM_RW_OFFSET 0x0A
+#define PM8XXX_ALARM_CTRL_OFFSET 0x01
+#define PM8XXX_RTC_WRITE_OFFSET 0x02
+#define PM8XXX_RTC_READ_OFFSET 0x06
+#define PM8XXX_ALARM_RW_OFFSET 0x0A
/* RTC_CTRL register bit fields */
-#define PM8xxx_RTC_ENABLE BIT(7)
-#define PM8xxx_RTC_ALARM_ENABLE BIT(1)
-#define PM8xxx_RTC_ABORT_ENABLE BIT(0)
+#define PM8xxx_RTC_ENABLE BIT(7)
+#define PM8xxx_RTC_ALARM_ENABLE BIT(1)
+#define PM8xxx_RTC_ALARM_CLEAR BIT(0)
+#define PM8xxx_RTC_ABORT_ENABLE BIT(0)
-#define PM8xxx_RTC_ALARM_CLEAR BIT(0)
-
-#define NUM_8_BIT_RTC_REGS 0x4
+#define NUM_8_BIT_RTC_REGS 0x4
/**
- * struct pm8xxx_rtc - rtc driver internal structure
- * @rtc: rtc device for this driver
- * @rtc_alarm_irq: rtc alarm irq number
+ * struct pm8xxx_rtc - rtc driver internal structure
+ * @rtc: rtc device for this driver.
+ * @rtc_alarm_irq: rtc alarm irq number.
+ * @rtc_base: address of rtc control register.
+ * @rtc_read_base: base address of read registers.
+ * @rtc_write_base: base address of write registers.
+ * @alarm_rw_base: base address of alarm registers.
+ * @ctrl_reg: rtc control register.
+ * @rtc_dev: device structure.
+ * @ctrl_reg_lock: spinlock protecting access to ctrl_reg.
*/
struct pm8xxx_rtc {
struct rtc_device *rtc;
@@ -57,9 +63,8 @@
* The RTC registers need to be read/written one byte at a time. This is a
* hardware limitation.
*/
-
static int pm8xxx_read_wrapper(struct pm8xxx_rtc *rtc_dd, u8 *rtc_val,
- int base, int count)
+ int base, int count)
{
int i, rc;
struct device *parent = rtc_dd->rtc_dev->parent;
@@ -67,7 +72,7 @@
for (i = 0; i < count; i++) {
rc = pm8xxx_readb(parent, base + i, &rtc_val[i]);
if (rc < 0) {
- dev_err(rtc_dd->rtc_dev, "PM8xxx read failed\n");
+ dev_err(rtc_dd->rtc_dev, "PMIC read failed\n");
return rc;
}
}
@@ -76,7 +81,7 @@
}
static int pm8xxx_write_wrapper(struct pm8xxx_rtc *rtc_dd, u8 *rtc_val,
- int base, int count)
+ int base, int count)
{
int i, rc;
struct device *parent = rtc_dd->rtc_dev->parent;
@@ -84,7 +89,7 @@
for (i = 0; i < count; i++) {
rc = pm8xxx_writeb(parent, base + i, rtc_val[i]);
if (rc < 0) {
- dev_err(rtc_dd->rtc_dev, "PM8xxx write failed\n");
+ dev_err(rtc_dd->rtc_dev, "PMIC write failed\n");
return rc;
}
}
@@ -92,7 +97,6 @@
return 0;
}
-
/*
* Steps to write the RTC registers.
* 1. Disable alarm if enabled.
@@ -100,20 +104,19 @@
* 3. Write Byte[1], Byte[2], Byte[3] then Byte[0].
* 4. Enable alarm if disabled in step 1.
*/
-static int
-pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
+static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
- int rc;
+ int rc, i;
unsigned long secs, irq_flags;
- u8 value[4], reg = 0, alarm_enabled = 0, ctrl_reg;
+ u8 value[NUM_8_BIT_RTC_REGS], reg = 0, alarm_enabled = 0, ctrl_reg;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
rtc_tm_to_time(tm, &secs);
- value[0] = secs & 0xFF;
- value[1] = (secs >> 8) & 0xFF;
- value[2] = (secs >> 16) & 0xFF;
- value[3] = (secs >> 24) & 0xFF;
+ for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) {
+ value[i] = secs & 0xFF;
+ secs >>= 8;
+ }
dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs);
@@ -124,20 +127,21 @@
alarm_enabled = 1;
ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE;
rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base,
- 1);
+ 1);
if (rc < 0) {
- dev_err(dev, "PM8xxx write failed\n");
+ dev_err(dev, "Write to RTC control register "
+ "failed\n");
goto rtc_rw_fail;
}
+ rtc_dd->ctrl_reg = ctrl_reg;
} else
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
- /* Write Byte[1], Byte[2], Byte[3], Byte[0] */
/* Write 0 to Byte[0] */
reg = 0;
rc = pm8xxx_write_wrapper(rtc_dd, ®, rtc_dd->rtc_write_base, 1);
if (rc < 0) {
- dev_err(dev, "PM8xxx write failed\n");
+ dev_err(dev, "Write to RTC write data register failed\n");
goto rtc_rw_fail;
}
@@ -145,14 +149,14 @@
rc = pm8xxx_write_wrapper(rtc_dd, value + 1,
rtc_dd->rtc_write_base + 1, 3);
if (rc < 0) {
- dev_err(dev, "Write to RTC registers failed\n");
+ dev_err(dev, "Write to RTC write data register failed\n");
goto rtc_rw_fail;
}
/* Write Byte[0] */
rc = pm8xxx_write_wrapper(rtc_dd, value, rtc_dd->rtc_write_base, 1);
if (rc < 0) {
- dev_err(dev, "Write to RTC register failed\n");
+ dev_err(dev, "Write to RTC write data register failed\n");
goto rtc_rw_fail;
}
@@ -161,13 +165,13 @@
rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base,
1);
if (rc < 0) {
- dev_err(dev, "PM8xxx write failed\n");
+ dev_err(dev, "Write to RTC control register "
+ "failed\n");
goto rtc_rw_fail;
}
+ rtc_dd->ctrl_reg = ctrl_reg;
}
- rtc_dd->ctrl_reg = ctrl_reg;
-
rtc_rw_fail:
if (alarm_enabled)
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
@@ -175,18 +179,17 @@
return rc;
}
-static int
-pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
+static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
int rc;
- u8 value[4], reg;
+ u8 value[NUM_8_BIT_RTC_REGS], reg;
unsigned long secs;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
rc = pm8xxx_read_wrapper(rtc_dd, value, rtc_dd->rtc_read_base,
NUM_8_BIT_RTC_REGS);
if (rc < 0) {
- dev_err(dev, "RTC time read failed\n");
+ dev_err(dev, "RTC read data register failed\n");
return rc;
}
@@ -196,7 +199,7 @@
*/
rc = pm8xxx_read_wrapper(rtc_dd, ®, rtc_dd->rtc_read_base, 1);
if (rc < 0) {
- dev_err(dev, "PM8xxx read failed\n");
+ dev_err(dev, "RTC read data register failed\n");
return rc;
}
@@ -204,96 +207,76 @@
rc = pm8xxx_read_wrapper(rtc_dd, value,
rtc_dd->rtc_read_base, NUM_8_BIT_RTC_REGS);
if (rc < 0) {
- dev_err(dev, "RTC time read failed\n");
+ dev_err(dev, "RTC read data register failed\n");
return rc;
}
}
- secs = value[0] | (value[1] << 8) | (value[2] << 16) \
- | (value[3] << 24);
+ secs = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24);
rtc_time_to_tm(secs, tm);
rc = rtc_valid_tm(tm);
if (rc < 0) {
- dev_err(dev, "Invalid time read from PM8xxx\n");
+ dev_err(dev, "Invalid time read from RTC\n");
return rc;
}
dev_dbg(dev, "secs = %lu, h:m:s == %d:%d:%d, d/m/y = %d/%d/%d\n",
- secs, tm->tm_hour, tm->tm_min, tm->tm_sec,
- tm->tm_mday, tm->tm_mon, tm->tm_year);
+ secs, tm->tm_hour, tm->tm_min, tm->tm_sec,
+ tm->tm_mday, tm->tm_mon, tm->tm_year);
return 0;
}
-static int
-pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
- int rc;
- u8 value[4], ctrl_reg;
- unsigned long secs, secs_rtc, irq_flags;
+ int rc, i;
+ u8 value[NUM_8_BIT_RTC_REGS], ctrl_reg;
+ unsigned long secs, irq_flags;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
- struct rtc_time rtc_tm;
rtc_tm_to_time(&alarm->time, &secs);
- /*
- * Read the current RTC time and verify if the alarm time is in the
- * past. If yes, return invalid.
- */
- rc = pm8xxx_rtc_read_time(dev, &rtc_tm);
- if (rc < 0) {
- dev_err(dev, "Unamble to read RTC time\n");
- return -EINVAL;
+ for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) {
+ value[i] = secs & 0xFF;
+ secs >>= 8;
}
- rtc_tm_to_time(&rtc_tm, &secs_rtc);
- if (secs < secs_rtc) {
- dev_err(dev, "Trying to set alarm in the past\n");
- return -EINVAL;
- }
-
- value[0] = secs & 0xFF;
- value[1] = (secs >> 8) & 0xFF;
- value[2] = (secs >> 16) & 0xFF;
- value[3] = (secs >> 24) & 0xFF;
-
spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
rc = pm8xxx_write_wrapper(rtc_dd, value, rtc_dd->alarm_rw_base,
NUM_8_BIT_RTC_REGS);
if (rc < 0) {
- dev_err(dev, "Write to RTC ALARM registers failed\n");
+ dev_err(dev, "Write to RTC ALARM register failed\n");
goto rtc_rw_fail;
}
ctrl_reg = rtc_dd->ctrl_reg;
- ctrl_reg = (alarm->enabled) ? (ctrl_reg | PM8xxx_RTC_ALARM_ENABLE) :
+ ctrl_reg = alarm->enabled ? (ctrl_reg | PM8xxx_RTC_ALARM_ENABLE) :
(ctrl_reg & ~PM8xxx_RTC_ALARM_ENABLE);
rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
if (rc < 0) {
- dev_err(dev, "PM8xxx write failed\n");
+ dev_err(dev, "Write to RTC control register failed\n");
goto rtc_rw_fail;
}
rtc_dd->ctrl_reg = ctrl_reg;
dev_dbg(dev, "Alarm Set for h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n",
- alarm->time.tm_hour, alarm->time.tm_min,
- alarm->time.tm_sec, alarm->time.tm_mday,
- alarm->time.tm_mon, alarm->time.tm_year);
+ alarm->time.tm_hour, alarm->time.tm_min,
+ alarm->time.tm_sec, alarm->time.tm_mday,
+ alarm->time.tm_mon, alarm->time.tm_year);
rtc_rw_fail:
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
return rc;
}
-static int
-pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
int rc;
- u8 value[4];
+ u8 value[NUM_8_BIT_RTC_REGS];
unsigned long secs;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
@@ -304,28 +287,25 @@
return rc;
}
- secs = value[0] | (value[1] << 8) | (value[2] << 16) | \
- (value[3] << 24);
+ secs = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24);
rtc_time_to_tm(secs, &alarm->time);
rc = rtc_valid_tm(&alarm->time);
if (rc < 0) {
- dev_err(dev, "Invalid time read from PM8xxx\n");
+ dev_err(dev, "Invalid alarm time read from RTC\n");
return rc;
}
dev_dbg(dev, "Alarm set for - h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n",
- alarm->time.tm_hour, alarm->time.tm_min,
+ alarm->time.tm_hour, alarm->time.tm_min,
alarm->time.tm_sec, alarm->time.tm_mday,
alarm->time.tm_mon, alarm->time.tm_year);
return 0;
}
-
-static int
-pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+static int pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
{
int rc;
unsigned long irq_flags;
@@ -334,12 +314,12 @@
spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
ctrl_reg = rtc_dd->ctrl_reg;
- ctrl_reg = (enabled) ? (ctrl_reg | PM8xxx_RTC_ALARM_ENABLE) :
+ ctrl_reg = (enable) ? (ctrl_reg | PM8xxx_RTC_ALARM_ENABLE) :
(ctrl_reg & ~PM8xxx_RTC_ALARM_ENABLE);
rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
if (rc < 0) {
- dev_err(dev, "PM8xxx write failed\n");
+ dev_err(dev, "Write to RTC control register failed\n");
goto rtc_rw_fail;
}
@@ -375,7 +355,8 @@
rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
if (rc < 0) {
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
- dev_err(rtc_dd->rtc_dev, "PM8xxx write failed!\n");
+ dev_err(rtc_dd->rtc_dev, "Write to RTC control register "
+ "failed\n");
goto rtc_alarm_handled;
}
@@ -386,7 +367,8 @@
rc = pm8xxx_read_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base +
PM8XXX_ALARM_CTRL_OFFSET, 1);
if (rc < 0) {
- dev_err(rtc_dd->rtc_dev, "PM8xxx write failed!\n");
+ dev_err(rtc_dd->rtc_dev, "RTC Alarm control register read "
+ "failed\n");
goto rtc_alarm_handled;
}
@@ -394,7 +376,8 @@
rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base +
PM8XXX_ALARM_CTRL_OFFSET, 1);
if (rc < 0)
- dev_err(rtc_dd->rtc_dev, "PM8xxx write failed!\n");
+ dev_err(rtc_dd->rtc_dev, "Write to RTC Alarm control register"
+ " failed\n");
rtc_alarm_handled:
return IRQ_HANDLED;
@@ -408,7 +391,7 @@
struct pm8xxx_rtc *rtc_dd;
struct resource *rtc_resource;
const struct pm8xxx_rtc_platform_data *pdata =
- pdev->dev.platform_data;
+ dev_get_platdata(&pdev->dev);
if (pdata != NULL)
rtc_write_enable = pdata->rtc_write_enable;
@@ -419,7 +402,7 @@
return -ENOMEM;
}
- /* Initialise spinlock to protect RTC cntrol register */
+ /* Initialise spinlock to protect RTC control register */
spin_lock_init(&rtc_dd->ctrl_reg_lock);
rtc_dd->rtc_alarm_irq = platform_get_irq(pdev, 0);
@@ -444,12 +427,12 @@
rtc_dd->rtc_read_base = rtc_dd->rtc_base + PM8XXX_RTC_READ_OFFSET;
rtc_dd->alarm_rw_base = rtc_dd->rtc_base + PM8XXX_ALARM_RW_OFFSET;
- rtc_dd->rtc_dev = &(pdev->dev);
+ rtc_dd->rtc_dev = &pdev->dev;
/* Check if the RTC is on, else turn it on */
rc = pm8xxx_read_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
if (rc < 0) {
- dev_err(&pdev->dev, "PM8xxx read failed!\n");
+ dev_err(&pdev->dev, "RTC control register read failed!\n");
goto fail_rtc_enable;
}
@@ -458,7 +441,8 @@
rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base,
1);
if (rc < 0) {
- dev_err(&pdev->dev, "PM8xxx write failed!\n");
+ dev_err(&pdev->dev, "Write to RTC control register "
+ "failed\n");
goto fail_rtc_enable;
}
}
@@ -510,7 +494,20 @@
return rc;
}
-#ifdef CONFIG_PM
+static int __devexit pm8xxx_rtc_remove(struct platform_device *pdev)
+{
+ struct pm8xxx_rtc *rtc_dd = platform_get_drvdata(pdev);
+
+ device_init_wakeup(&pdev->dev, 0);
+ free_irq(rtc_dd->rtc_alarm_irq, rtc_dd);
+ rtc_device_unregister(rtc_dd->rtc);
+ platform_set_drvdata(pdev, NULL);
+ kfree(rtc_dd);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
static int pm8xxx_rtc_resume(struct device *dev)
{
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
@@ -530,24 +527,9 @@
return 0;
}
-
-static const struct dev_pm_ops pm8xxx_rtc_pm_ops = {
- .suspend = pm8xxx_rtc_suspend,
- .resume = pm8xxx_rtc_resume,
-};
#endif
-static int __devexit pm8xxx_rtc_remove(struct platform_device *pdev)
-{
- struct pm8xxx_rtc *rtc_dd = platform_get_drvdata(pdev);
- device_init_wakeup(&pdev->dev, 0);
- free_irq(rtc_dd->rtc_alarm_irq, rtc_dd);
- rtc_device_unregister(rtc_dd->rtc);
- platform_set_drvdata(pdev, NULL);
- kfree(rtc_dd);
-
- return 0;
-}
+static SIMPLE_DEV_PM_OPS(pm8xxx_rtc_pm_ops, pm8xxx_rtc_suspend, pm8xxx_rtc_resume);
static void pm8xxx_rtc_shutdown(struct platform_device *pdev)
{
@@ -572,7 +554,7 @@
reg &= ~PM8xxx_RTC_ALARM_ENABLE;
rc = pm8xxx_write_wrapper(rtc_dd, ®, rtc_dd->rtc_base, 1);
if (rc < 0) {
- dev_err(rtc_dd->rtc_dev, "PM8xxx write failed\n");
+ dev_err(rtc_dd->rtc_dev, "Disabling alarm failed\n");
goto fail_alarm_disable;
}
@@ -580,7 +562,7 @@
rc = pm8xxx_write_wrapper(rtc_dd, value,
rtc_dd->alarm_rw_base, NUM_8_BIT_RTC_REGS);
if (rc < 0)
- dev_err(rtc_dd->rtc_dev, "PM8xxx write failed\n");
+ dev_err(rtc_dd->rtc_dev, "Clearing alarm failed\n");
fail_alarm_disable:
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
@@ -594,23 +576,11 @@
.driver = {
.name = PM8XXX_RTC_DEV_NAME,
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
.pm = &pm8xxx_rtc_pm_ops,
-#endif
},
};
-static int __init pm8xxx_rtc_init(void)
-{
- return platform_driver_register(&pm8xxx_rtc_driver);
-}
-module_init(pm8xxx_rtc_init);
-
-static void __exit pm8xxx_rtc_exit(void)
-{
- platform_driver_unregister(&pm8xxx_rtc_driver);
-}
-module_exit(pm8xxx_rtc_exit);
+module_platform_driver(pm8xxx_rtc_driver);
MODULE_ALIAS("platform:rtc-pm8xxx");
MODULE_DESCRIPTION("PMIC8xxx RTC driver");
diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c
index ef9c77d..fab3586 100644
--- a/drivers/scsi/isci/phy.c
+++ b/drivers/scsi/isci/phy.c
@@ -293,18 +293,6 @@
writel(sp_timeouts, &llr->sas_phy_timeouts);
- sp_timeouts = readl(&iphy->link_layer_registers->sas_phy_timeouts);
-
- /* Clear the default 0x36 (54us) RATE_CHANGE timeout value. */
- sp_timeouts &= ~SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0xFF);
-
- /* Set RATE_CHANGE timeout value to 0x3B (59us). This ensures SCU can
- * lock with 3Gb drive when SCU max rate is set to 1.5Gb.
- */
- sp_timeouts |= SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0x3B);
-
- writel(sp_timeouts, &iphy->link_layer_registers->sas_phy_timeouts);
-
if (is_a2(ihost->pdev)) {
/* Program the max ARB time for the PHY to 700us so we
* inter-operate with the PMC expander which shuts down
diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index 1756897..706fba7 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -2,51 +2,61 @@
# Kernel configuration file for the UFS Host Controller
#
# This code is based on drivers/scsi/ufs/Kconfig
-# Copyright (C) 2011 Samsung Samsung India Software Operations
+# Copyright (C) 2011-2013 Samsung India Software Operations
#
-# Santosh Yaraganavi <santosh.sy@samsung.com>
-# Vinayak Holikatti <h.vinayak@samsung.com>
-
+# Authors:
+# Santosh Yaraganavi <santosh.sy@samsung.com>
+# Vinayak Holikatti <h.vinayak@samsung.com>
+#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
-
+# See the COPYING file in the top-level directory or visit
+# <http://www.gnu.org/licenses/gpl-2.0.html>
+#
# 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.
-
-# NO WARRANTY
-# THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
-# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
-# LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
-# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
-# solely responsible for determining the appropriateness of using and
-# distributing the Program and assumes all risks associated with its
-# exercise of rights under this Agreement, including but not limited to
-# the risks and costs of program errors, damage to or loss of data,
-# programs or equipment, and unavailability or interruption of operations.
-
-# DISCLAIMER OF LIABILITY
-# NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
-# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
-# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
-# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-# USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
-# HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-# USA.
+#
+# This program is provided "AS IS" and "WITH ALL FAULTS" and
+# without warranty of any kind. You are solely responsible for
+# determining the appropriateness of using and distributing
+# the program and assume all risks associated with your exercise
+# of rights with respect to the program, including but not limited
+# to infringement of third party rights, the risks and costs of
+# program errors, damage to or loss of data, programs or equipment,
+# and unavailability or interruption of operations. Under no
+# circumstances will the contributor of this Program be liable for
+# any damages of any kind arising from your use or distribution of
+# this program.
config SCSI_UFSHCD
- tristate "Universal Flash Storage host controller driver"
- depends on PCI && SCSI
+ tristate "Universal Flash Storage Controller Driver Core"
+ depends on SCSI
---help---
- This is a generic driver which supports PCIe UFS Host controllers.
+ This selects the support for UFS devices in Linux, say Y and make
+ sure that you know the name of your UFS host adapter (the card
+ inside your computer that "speaks" the UFS protocol, also
+ called UFS Host Controller), because you will be asked for it.
+ The module will be called ufshcd.
+
+ To compile this driver as a module, choose M here and read
+ <file:Documentation/scsi/ufs.txt>.
+ However, do not compile this as a module if your root file system
+ (the one containing the directory /) is located on a UFS device.
+
+config SCSI_UFSHCD_PCI
+ tristate "PCI bus based UFS Controller support"
+ depends on SCSI_UFSHCD && PCI
+ ---help---
+ This selects the PCI UFS Host Controller Interface. Select this if
+ you have UFS Host Controller with PCI Interface.
+
+ If you have a controller with this interface, say Y or M here.
+
+ If unsure, say N.
config SCSI_UFS_TEST
tristate "Universal Flash Storage host controller driver unit-tests"
diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile
index 489058d..bbcc202 100644
--- a/drivers/scsi/ufs/Makefile
+++ b/drivers/scsi/ufs/Makefile
@@ -1,3 +1,4 @@
# UFSHCD makefile
obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o
+obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o
obj-$(CONFIG_SCSI_UFS_TEST) += ufs_test.o
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index b207529..139bc06 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -2,45 +2,35 @@
* Universal Flash Storage Host controller driver
*
* This code is based on drivers/scsi/ufs/ufs.h
- * Copyright (C) 2011-2012 Samsung India Software Operations
+ * Copyright (C) 2011-2013 Samsung India Software Operations
*
- * Santosh Yaraganavi <santosh.sy@samsung.com>
- * Vinayak Holikatti <h.vinayak@samsung.com>
+ * Authors:
+ * Santosh Yaraganavi <santosh.sy@samsung.com>
+ * Vinayak Holikatti <h.vinayak@samsung.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
+ * See the COPYING file in the top-level directory or visit
+ * <http://www.gnu.org/licenses/gpl-2.0.html>
*
* 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.
*
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * This program is provided "AS IS" and "WITH ALL FAULTS" and
+ * without warranty of any kind. You are solely responsible for
+ * determining the appropriateness of using and distributing
+ * the program and assume all risks associated with your exercise
+ * of rights with respect to the program, including but not limited
+ * to infringement of third party rights, the risks and costs of
+ * program errors, damage to or loss of data, programs or equipment,
+ * and unavailability or interruption of operations. Under no
+ * circumstances will the contributor of this Program be liable for
+ * any damages of any kind arising from your use or distribution of
+ * this program.
*/
#ifndef _UFS_H
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
new file mode 100644
index 0000000..5cb1d75
--- /dev/null
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -0,0 +1,211 @@
+/*
+ * Universal Flash Storage Host controller PCI glue driver
+ *
+ * This code is based on drivers/scsi/ufs/ufshcd-pci.c
+ * Copyright (C) 2011-2013 Samsung India Software Operations
+ *
+ * Authors:
+ * Santosh Yaraganavi <santosh.sy@samsung.com>
+ * Vinayak Holikatti <h.vinayak@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * See the COPYING file in the top-level directory or visit
+ * <http://www.gnu.org/licenses/gpl-2.0.html>
+ *
+ * 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 program is provided "AS IS" and "WITH ALL FAULTS" and
+ * without warranty of any kind. You are solely responsible for
+ * determining the appropriateness of using and distributing
+ * the program and assume all risks associated with your exercise
+ * of rights with respect to the program, including but not limited
+ * to infringement of third party rights, the risks and costs of
+ * program errors, damage to or loss of data, programs or equipment,
+ * and unavailability or interruption of operations. Under no
+ * circumstances will the contributor of this Program be liable for
+ * any damages of any kind arising from your use or distribution of
+ * this program.
+ */
+
+#include "ufshcd.h"
+#include <linux/pci.h>
+
+#ifdef CONFIG_PM
+/**
+ * ufshcd_pci_suspend - suspend power management function
+ * @pdev: pointer to PCI device handle
+ * @state: power state
+ *
+ * Returns -ENOSYS
+ */
+static int ufshcd_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ /*
+ * TODO:
+ * 1. Call ufshcd_suspend
+ * 2. Do bus specific power management
+ */
+
+ return -ENOSYS;
+}
+
+/**
+ * ufshcd_pci_resume - resume power management function
+ * @pdev: pointer to PCI device handle
+ *
+ * Returns -ENOSYS
+ */
+static int ufshcd_pci_resume(struct pci_dev *pdev)
+{
+ /*
+ * TODO:
+ * 1. Call ufshcd_resume.
+ * 2. Do bus specific wake up
+ */
+
+ return -ENOSYS;
+}
+#endif /* CONFIG_PM */
+
+/**
+ * ufshcd_pci_shutdown - main function to put the controller in reset state
+ * @pdev: pointer to PCI device handle
+ */
+static void ufshcd_pci_shutdown(struct pci_dev *pdev)
+{
+ ufshcd_hba_stop((struct ufs_hba *)pci_get_drvdata(pdev));
+}
+
+/**
+ * ufshcd_pci_remove - de-allocate PCI/SCSI host and host memory space
+ * data structure memory
+ * @pdev - pointer to PCI handle
+ */
+static void ufshcd_pci_remove(struct pci_dev *pdev)
+{
+ struct ufs_hba *hba = pci_get_drvdata(pdev);
+
+ disable_irq(pdev->irq);
+ free_irq(pdev->irq, hba);
+ ufshcd_remove(hba);
+ pci_release_regions(pdev);
+ pci_set_drvdata(pdev, NULL);
+ pci_clear_master(pdev);
+ pci_disable_device(pdev);
+}
+
+/**
+ * ufshcd_set_dma_mask - Set dma mask based on the controller
+ * addressing capability
+ * @pdev: PCI device structure
+ *
+ * Returns 0 for success, non-zero for failure
+ */
+static int ufshcd_set_dma_mask(struct pci_dev *pdev)
+{
+ int err;
+
+ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
+ && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
+ return 0;
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (!err)
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ return err;
+}
+
+/**
+ * ufshcd_pci_probe - probe routine of the driver
+ * @pdev: pointer to PCI device handle
+ * @id: PCI device id
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int
+ufshcd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct ufs_hba *hba;
+ void __iomem *mmio_base;
+ int err;
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "pci_enable_device failed\n");
+ goto out_error;
+ }
+
+ pci_set_master(pdev);
+
+
+ err = pci_request_regions(pdev, UFSHCD);
+ if (err < 0) {
+ dev_err(&pdev->dev, "request regions failed\n");
+ goto out_disable;
+ }
+
+ mmio_base = pci_ioremap_bar(pdev, 0);
+ if (!mmio_base) {
+ dev_err(&pdev->dev, "memory map failed\n");
+ err = -ENOMEM;
+ goto out_release_regions;
+ }
+
+ err = ufshcd_set_dma_mask(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "set dma mask failed\n");
+ goto out_iounmap;
+ }
+
+ err = ufshcd_init(&pdev->dev, &hba, mmio_base, pdev->irq);
+ if (err) {
+ dev_err(&pdev->dev, "Initialization failed\n");
+ goto out_iounmap;
+ }
+
+ pci_set_drvdata(pdev, hba);
+
+ return 0;
+
+out_iounmap:
+ iounmap(mmio_base);
+out_release_regions:
+ pci_release_regions(pdev);
+out_disable:
+ pci_clear_master(pdev);
+ pci_disable_device(pdev);
+out_error:
+ return err;
+}
+
+static DEFINE_PCI_DEVICE_TABLE(ufshcd_pci_tbl) = {
+ { PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { } /* terminate list */
+};
+
+MODULE_DEVICE_TABLE(pci, ufshcd_pci_tbl);
+
+static struct pci_driver ufshcd_pci_driver = {
+ .name = UFSHCD,
+ .id_table = ufshcd_pci_tbl,
+ .probe = ufshcd_pci_probe,
+ .remove = ufshcd_pci_remove,
+ .shutdown = ufshcd_pci_shutdown,
+#ifdef CONFIG_PM
+ .suspend = ufshcd_pci_suspend,
+ .resume = ufshcd_pci_resume,
+#endif
+};
+
+module_pci_driver(ufshcd_pci_driver);
+
+MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>");
+MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>");
+MODULE_DESCRIPTION("UFS host controller PCI glue driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(UFSHCD_DRIVER_VERSION);
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 58f4ba6..60fd40c 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1,77 +1,39 @@
/*
- * Universal Flash Storage Host controller driver
+ * Universal Flash Storage Host controller driver Core
*
* This code is based on drivers/scsi/ufs/ufshcd.c
- * Copyright (C) 2011-2012 Samsung India Software Operations
+ * Copyright (C) 2011-2013 Samsung India Software Operations
*
- * Santosh Yaraganavi <santosh.sy@samsung.com>
- * Vinayak Holikatti <h.vinayak@samsung.com>
+ * Authors:
+ * Santosh Yaraganavi <santosh.sy@samsung.com>
+ * Vinayak Holikatti <h.vinayak@samsung.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
+ * See the COPYING file in the top-level directory or visit
+ * <http://www.gnu.org/licenses/gpl-2.0.html>
*
* 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.
*
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * This program is provided "AS IS" and "WITH ALL FAULTS" and
+ * without warranty of any kind. You are solely responsible for
+ * determining the appropriateness of using and distributing
+ * the program and assume all risks associated with your exercise
+ * of rights with respect to the program, including but not limited
+ * to infringement of third party rights, the risks and costs of
+ * program errors, damage to or loss of data, programs or equipment,
+ * and unavailability or interruption of operations. Under no
+ * circumstances will the contributor of this Program be liable for
+ * any damages of any kind arising from your use or distribution of
+ * this program.
*/
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/workqueue.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/wait.h>
-#include <linux/bitops.h>
-
-#include <asm/irq.h>
-#include <asm/byteorder.h>
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_tcq.h>
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_eh.h>
-
-#include "ufs.h"
-#include "ufshci.h"
-
-#define UFSHCD "ufshcd"
-#define UFSHCD_DRIVER_VERSION "0.1"
+#include "ufshcd.h"
enum {
UFSHCD_MAX_CHANNEL = 0,
@@ -102,121 +64,6 @@
};
/**
- * struct uic_command - UIC command structure
- * @command: UIC command
- * @argument1: UIC command argument 1
- * @argument2: UIC command argument 2
- * @argument3: UIC command argument 3
- * @cmd_active: Indicate if UIC command is outstanding
- * @result: UIC command result
- */
-struct uic_command {
- u32 command;
- u32 argument1;
- u32 argument2;
- u32 argument3;
- int cmd_active;
- int result;
-};
-
-/**
- * struct ufs_hba - per adapter private structure
- * @mmio_base: UFSHCI base register address
- * @ucdl_base_addr: UFS Command Descriptor base address
- * @utrdl_base_addr: UTP Transfer Request Descriptor base address
- * @utmrdl_base_addr: UTP Task Management Descriptor base address
- * @ucdl_dma_addr: UFS Command Descriptor DMA address
- * @utrdl_dma_addr: UTRDL DMA address
- * @utmrdl_dma_addr: UTMRDL DMA address
- * @host: Scsi_Host instance of the driver
- * @pdev: PCI device handle
- * @lrb: local reference block
- * @outstanding_tasks: Bits representing outstanding task requests
- * @outstanding_reqs: Bits representing outstanding transfer requests
- * @capabilities: UFS Controller Capabilities
- * @nutrs: Transfer Request Queue depth supported by controller
- * @nutmrs: Task Management Queue depth supported by controller
- * @active_uic_cmd: handle of active UIC command
- * @ufshcd_tm_wait_queue: wait queue for task management
- * @tm_condition: condition variable for task management
- * @ufshcd_state: UFSHCD states
- * @int_enable_mask: Interrupt Mask Bits
- * @uic_workq: Work queue for UIC completion handling
- * @feh_workq: Work queue for fatal controller error handling
- * @errors: HBA errors
- */
-struct ufs_hba {
- void __iomem *mmio_base;
-
- /* Virtual memory reference */
- struct utp_transfer_cmd_desc *ucdl_base_addr;
- struct utp_transfer_req_desc *utrdl_base_addr;
- struct utp_task_req_desc *utmrdl_base_addr;
-
- /* DMA memory reference */
- dma_addr_t ucdl_dma_addr;
- dma_addr_t utrdl_dma_addr;
- dma_addr_t utmrdl_dma_addr;
-
- struct Scsi_Host *host;
- struct pci_dev *pdev;
-
- struct ufshcd_lrb *lrb;
-
- unsigned long outstanding_tasks;
- unsigned long outstanding_reqs;
-
- u32 capabilities;
- int nutrs;
- int nutmrs;
- u32 ufs_version;
-
- struct uic_command active_uic_cmd;
- wait_queue_head_t ufshcd_tm_wait_queue;
- unsigned long tm_condition;
-
- u32 ufshcd_state;
- u32 int_enable_mask;
-
- /* Work Queues */
- struct work_struct uic_workq;
- struct work_struct feh_workq;
-
- /* HBA Errors */
- u32 errors;
-};
-
-/**
- * struct ufshcd_lrb - local reference block
- * @utr_descriptor_ptr: UTRD address of the command
- * @ucd_cmd_ptr: UCD address of the command
- * @ucd_rsp_ptr: Response UPIU address for this command
- * @ucd_prdt_ptr: PRDT address of the command
- * @cmd: pointer to SCSI command
- * @sense_buffer: pointer to sense buffer address of the SCSI command
- * @sense_bufflen: Length of the sense buffer
- * @scsi_status: SCSI status of the command
- * @command_type: SCSI, UFS, Query.
- * @task_tag: Task tag of the command
- * @lun: LUN of the command
- */
-struct ufshcd_lrb {
- struct utp_transfer_req_desc *utr_descriptor_ptr;
- struct utp_upiu_cmd *ucd_cmd_ptr;
- struct utp_upiu_rsp *ucd_rsp_ptr;
- struct ufshcd_sg_entry *ucd_prdt_ptr;
-
- struct scsi_cmnd *cmd;
- u8 *sense_buffer;
- unsigned int sense_bufflen;
- int scsi_status;
-
- int command_type;
- int task_tag;
- unsigned int lun;
-};
-
-/**
* ufshcd_get_ufs_version - Get the UFS version supported by the HBA
* @hba - Pointer to adapter instance
*
@@ -335,21 +182,21 @@
if (hba->utmrdl_base_addr) {
utmrdl_size = sizeof(struct utp_task_req_desc) * hba->nutmrs;
- dma_free_coherent(&hba->pdev->dev, utmrdl_size,
+ dma_free_coherent(hba->dev, utmrdl_size,
hba->utmrdl_base_addr, hba->utmrdl_dma_addr);
}
if (hba->utrdl_base_addr) {
utrdl_size =
(sizeof(struct utp_transfer_req_desc) * hba->nutrs);
- dma_free_coherent(&hba->pdev->dev, utrdl_size,
+ dma_free_coherent(hba->dev, utrdl_size,
hba->utrdl_base_addr, hba->utrdl_dma_addr);
}
if (hba->ucdl_base_addr) {
ucdl_size =
(sizeof(struct utp_transfer_cmd_desc) * hba->nutrs);
- dma_free_coherent(&hba->pdev->dev, ucdl_size,
+ dma_free_coherent(hba->dev, ucdl_size,
hba->ucdl_base_addr, hba->ucdl_dma_addr);
}
}
@@ -429,15 +276,6 @@
}
/**
- * ufshcd_hba_stop - Send controller to reset state
- * @hba: per adapter instance
- */
-static inline void ufshcd_hba_stop(struct ufs_hba *hba)
-{
- writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
-}
-
-/**
* ufshcd_hba_start - Start controller initialization sequence
* @hba: per adapter instance
*/
@@ -724,7 +562,7 @@
/* Allocate memory for UTP command descriptors */
ucdl_size = (sizeof(struct utp_transfer_cmd_desc) * hba->nutrs);
- hba->ucdl_base_addr = dma_alloc_coherent(&hba->pdev->dev,
+ hba->ucdl_base_addr = dma_alloc_coherent(hba->dev,
ucdl_size,
&hba->ucdl_dma_addr,
GFP_KERNEL);
@@ -737,7 +575,7 @@
*/
if (!hba->ucdl_base_addr ||
WARN_ON(hba->ucdl_dma_addr & (PAGE_SIZE - 1))) {
- dev_err(&hba->pdev->dev,
+ dev_err(hba->dev,
"Command Descriptor Memory allocation failed\n");
goto out;
}
@@ -747,13 +585,13 @@
* UFSHCI requires 1024 byte alignment of UTRD
*/
utrdl_size = (sizeof(struct utp_transfer_req_desc) * hba->nutrs);
- hba->utrdl_base_addr = dma_alloc_coherent(&hba->pdev->dev,
+ hba->utrdl_base_addr = dma_alloc_coherent(hba->dev,
utrdl_size,
&hba->utrdl_dma_addr,
GFP_KERNEL);
if (!hba->utrdl_base_addr ||
WARN_ON(hba->utrdl_dma_addr & (PAGE_SIZE - 1))) {
- dev_err(&hba->pdev->dev,
+ dev_err(hba->dev,
"Transfer Descriptor Memory allocation failed\n");
goto out;
}
@@ -763,13 +601,13 @@
* UFSHCI requires 1024 byte alignment of UTMRD
*/
utmrdl_size = sizeof(struct utp_task_req_desc) * hba->nutmrs;
- hba->utmrdl_base_addr = dma_alloc_coherent(&hba->pdev->dev,
+ hba->utmrdl_base_addr = dma_alloc_coherent(hba->dev,
utmrdl_size,
&hba->utmrdl_dma_addr,
GFP_KERNEL);
if (!hba->utmrdl_base_addr ||
WARN_ON(hba->utmrdl_dma_addr & (PAGE_SIZE - 1))) {
- dev_err(&hba->pdev->dev,
+ dev_err(hba->dev,
"Task Management Descriptor Memory allocation failed\n");
goto out;
}
@@ -777,7 +615,7 @@
/* Allocate memory for local reference block */
hba->lrb = kcalloc(hba->nutrs, sizeof(struct ufshcd_lrb), GFP_KERNEL);
if (!hba->lrb) {
- dev_err(&hba->pdev->dev, "LRB Memory allocation failed\n");
+ dev_err(hba->dev, "LRB Memory allocation failed\n");
goto out;
}
return 0;
@@ -867,7 +705,7 @@
/* check if controller is ready to accept UIC commands */
if (((readl(hba->mmio_base + REG_CONTROLLER_STATUS)) &
UIC_COMMAND_READY) == 0x0) {
- dev_err(&hba->pdev->dev,
+ dev_err(hba->dev,
"Controller not ready"
" to accept UIC commands\n");
return -EIO;
@@ -912,7 +750,7 @@
/* check if device present */
reg = readl((hba->mmio_base + REG_CONTROLLER_STATUS));
if (!ufshcd_is_device_present(reg)) {
- dev_err(&hba->pdev->dev, "cc: Device not present\n");
+ dev_err(hba->dev, "cc: Device not present\n");
err = -ENXIO;
goto out;
}
@@ -924,7 +762,7 @@
if (!(ufshcd_get_lists_status(reg))) {
ufshcd_enable_run_stop_reg(hba);
} else {
- dev_err(&hba->pdev->dev,
+ dev_err(hba->dev,
"Host controller not ready to process requests");
err = -EIO;
goto out;
@@ -1005,7 +843,7 @@
if (retry) {
retry--;
} else {
- dev_err(&hba->pdev->dev,
+ dev_err(hba->dev,
"Controller enable failed\n");
return -EIO;
}
@@ -1084,7 +922,7 @@
/* start the initialization process */
if (ufshcd_initialize_hba(hba)) {
- dev_err(&hba->pdev->dev,
+ dev_err(hba->dev,
"Reset: Controller initialization failed\n");
return FAILED;
}
@@ -1167,7 +1005,7 @@
task_result = SUCCESS;
} else {
task_result = FAILED;
- dev_err(&hba->pdev->dev,
+ dev_err(hba->dev,
"trc: Invalid ocs = %x\n", ocs_value);
}
spin_unlock_irqrestore(hba->host->host_lock, flags);
@@ -1281,7 +1119,7 @@
/* check if the returned transfer response is valid */
result = ufshcd_is_valid_req_rsp(lrbp->ucd_rsp_ptr);
if (result) {
- dev_err(&hba->pdev->dev,
+ dev_err(hba->dev,
"Invalid response = %x\n", result);
break;
}
@@ -1310,7 +1148,7 @@
case OCS_FATAL_ERROR:
default:
result |= DID_ERROR << 16;
- dev_err(&hba->pdev->dev,
+ dev_err(hba->dev,
"OCS error from controller = %x\n", ocs);
break;
} /* end of switch */
@@ -1374,7 +1212,7 @@
!(ufshcd_get_uic_cmd_result(hba))) {
if (ufshcd_make_hba_operational(hba))
- dev_err(&hba->pdev->dev,
+ dev_err(hba->dev,
"cc: hba not operational state\n");
return;
}
@@ -1509,7 +1347,7 @@
free_slot = ufshcd_get_tm_free_slot(hba);
if (free_slot >= hba->nutmrs) {
spin_unlock_irqrestore(host->host_lock, flags);
- dev_err(&hba->pdev->dev, "Task management queue full\n");
+ dev_err(hba->dev, "Task management queue full\n");
err = FAILED;
goto out;
}
@@ -1552,7 +1390,7 @@
&hba->tm_condition) != 0),
60 * HZ);
if (!err) {
- dev_err(&hba->pdev->dev,
+ dev_err(hba->dev,
"Task management command timed-out\n");
err = FAILED;
goto out;
@@ -1688,23 +1526,13 @@
};
/**
- * ufshcd_shutdown - main function to put the controller in reset state
- * @pdev: pointer to PCI device handle
- */
-static void ufshcd_shutdown(struct pci_dev *pdev)
-{
- ufshcd_hba_stop((struct ufs_hba *)pci_get_drvdata(pdev));
-}
-
-#ifdef CONFIG_PM
-/**
* ufshcd_suspend - suspend power management function
- * @pdev: pointer to PCI device handle
+ * @hba: per adapter instance
* @state: power state
*
* Returns -ENOSYS
*/
-static int ufshcd_suspend(struct pci_dev *pdev, pm_message_t state)
+int ufshcd_suspend(struct ufs_hba *hba, pm_message_t state)
{
/*
* TODO:
@@ -1717,14 +1545,15 @@
return -ENOSYS;
}
+EXPORT_SYMBOL_GPL(ufshcd_suspend);
/**
* ufshcd_resume - resume power management function
- * @pdev: pointer to PCI device handle
+ * @hba: per adapter instance
*
* Returns -ENOSYS
*/
-static int ufshcd_resume(struct pci_dev *pdev)
+int ufshcd_resume(struct ufs_hba *hba)
{
/*
* TODO:
@@ -1737,7 +1566,7 @@
return -ENOSYS;
}
-#endif /* CONFIG_PM */
+EXPORT_SYMBOL_GPL(ufshcd_resume);
/**
* ufshcd_hba_free - free allocated memory for
@@ -1748,108 +1577,67 @@
{
iounmap(hba->mmio_base);
ufshcd_free_hba_memory(hba);
- pci_release_regions(hba->pdev);
}
/**
- * ufshcd_remove - de-allocate PCI/SCSI host and host memory space
+ * ufshcd_remove - de-allocate SCSI host and host memory space
* data structure memory
- * @pdev - pointer to PCI handle
+ * @hba - per adapter instance
*/
-static void ufshcd_remove(struct pci_dev *pdev)
+void ufshcd_remove(struct ufs_hba *hba)
{
- struct ufs_hba *hba = pci_get_drvdata(pdev);
-
/* disable interrupts */
ufshcd_int_config(hba, UFSHCD_INT_DISABLE);
- free_irq(pdev->irq, hba);
ufshcd_hba_stop(hba);
ufshcd_hba_free(hba);
scsi_remove_host(hba->host);
scsi_host_put(hba->host);
- pci_set_drvdata(pdev, NULL);
- pci_clear_master(pdev);
- pci_disable_device(pdev);
}
+EXPORT_SYMBOL_GPL(ufshcd_remove);
/**
- * ufshcd_set_dma_mask - Set dma mask based on the controller
- * addressing capability
- * @pdev: PCI device structure
- *
- * Returns 0 for success, non-zero for failure
- */
-static int ufshcd_set_dma_mask(struct ufs_hba *hba)
-{
- int err;
- u64 dma_mask;
-
- /*
- * If controller supports 64 bit addressing mode, then set the DMA
- * mask to 64-bit, else set the DMA mask to 32-bit
- */
- if (hba->capabilities & MASK_64_ADDRESSING_SUPPORT)
- dma_mask = DMA_BIT_MASK(64);
- else
- dma_mask = DMA_BIT_MASK(32);
-
- err = pci_set_dma_mask(hba->pdev, dma_mask);
- if (err)
- return err;
-
- err = pci_set_consistent_dma_mask(hba->pdev, dma_mask);
-
- return err;
-}
-
-/**
- * ufshcd_probe - probe routine of the driver
- * @pdev: pointer to PCI device handle
- * @id: PCI device id
- *
+ * ufshcd_init - Driver initialization routine
+ * @dev: pointer to device handle
+ * @hba_handle: driver private handle
+ * @mmio_base: base register address
+ * @irq: Interrupt line of device
* Returns 0 on success, non-zero value on failure
*/
-static int __devinit
-ufshcd_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
+ void __iomem *mmio_base, unsigned int irq)
{
struct Scsi_Host *host;
struct ufs_hba *hba;
int err;
- err = pci_enable_device(pdev);
- if (err) {
- dev_err(&pdev->dev, "pci_enable_device failed\n");
+ if (!dev) {
+ dev_err(dev,
+ "Invalid memory reference for dev is NULL\n");
+ err = -ENODEV;
goto out_error;
}
- pci_set_master(pdev);
+ if (!mmio_base) {
+ dev_err(dev,
+ "Invalid memory reference for mmio_base is NULL\n");
+ err = -ENODEV;
+ goto out_error;
+ }
host = scsi_host_alloc(&ufshcd_driver_template,
sizeof(struct ufs_hba));
if (!host) {
- dev_err(&pdev->dev, "scsi_host_alloc failed\n");
+ dev_err(dev, "scsi_host_alloc failed\n");
err = -ENOMEM;
- goto out_disable;
+ goto out_error;
}
hba = shost_priv(host);
-
- err = pci_request_regions(pdev, UFSHCD);
- if (err < 0) {
- dev_err(&pdev->dev, "request regions failed\n");
- goto out_host_put;
- }
-
- hba->mmio_base = pci_ioremap_bar(pdev, 0);
- if (!hba->mmio_base) {
- dev_err(&pdev->dev, "memory map failed\n");
- err = -ENOMEM;
- goto out_release_regions;
- }
-
hba->host = host;
- hba->pdev = pdev;
+ hba->dev = dev;
+ hba->mmio_base = mmio_base;
+ hba->irq = irq;
/* Read capabilities registers */
ufshcd_hba_capabilities(hba);
@@ -1857,17 +1645,11 @@
/* Get UFS version supported by the controller */
hba->ufs_version = ufshcd_get_ufs_version(hba);
- err = ufshcd_set_dma_mask(hba);
- if (err) {
- dev_err(&pdev->dev, "set dma mask failed\n");
- goto out_iounmap;
- }
-
/* Allocate memory for host memory space */
err = ufshcd_memory_alloc(hba);
if (err) {
- dev_err(&pdev->dev, "Memory allocation failed\n");
- goto out_iounmap;
+ dev_err(hba->dev, "Memory allocation failed\n");
+ goto out_disable;
}
/* Configure LRB */
@@ -1889,76 +1671,50 @@
INIT_WORK(&hba->feh_workq, ufshcd_fatal_err_handler);
/* IRQ registration */
- err = request_irq(pdev->irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
+ err = request_irq(irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
if (err) {
- dev_err(&pdev->dev, "request irq failed\n");
+ dev_err(hba->dev, "request irq failed\n");
goto out_lrb_free;
}
/* Enable SCSI tag mapping */
err = scsi_init_shared_tag_map(host, host->can_queue);
if (err) {
- dev_err(&pdev->dev, "init shared queue failed\n");
+ dev_err(hba->dev, "init shared queue failed\n");
goto out_free_irq;
}
- pci_set_drvdata(pdev, hba);
-
- err = scsi_add_host(host, &pdev->dev);
+ err = scsi_add_host(host, hba->dev);
if (err) {
- dev_err(&pdev->dev, "scsi_add_host failed\n");
+ dev_err(hba->dev, "scsi_add_host failed\n");
goto out_free_irq;
}
/* Initialization routine */
err = ufshcd_initialize_hba(hba);
if (err) {
- dev_err(&pdev->dev, "Initialization failed\n");
- goto out_free_irq;
+ dev_err(hba->dev, "Initialization failed\n");
+ goto out_remove_scsi_host;
}
+ *hba_handle = hba;
return 0;
+out_remove_scsi_host:
+ scsi_remove_host(hba->host);
out_free_irq:
- free_irq(pdev->irq, hba);
+ free_irq(irq, hba);
out_lrb_free:
ufshcd_free_hba_memory(hba);
-out_iounmap:
- iounmap(hba->mmio_base);
-out_release_regions:
- pci_release_regions(pdev);
-out_host_put:
- scsi_host_put(host);
out_disable:
- pci_clear_master(pdev);
- pci_disable_device(pdev);
+ scsi_host_put(host);
out_error:
return err;
}
+EXPORT_SYMBOL_GPL(ufshcd_init);
-static DEFINE_PCI_DEVICE_TABLE(ufshcd_pci_tbl) = {
- { PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { } /* terminate list */
-};
-
-MODULE_DEVICE_TABLE(pci, ufshcd_pci_tbl);
-
-static struct pci_driver ufshcd_pci_driver = {
- .name = UFSHCD,
- .id_table = ufshcd_pci_tbl,
- .probe = ufshcd_probe,
- .remove = __devexit_p(ufshcd_remove),
- .shutdown = ufshcd_shutdown,
-#ifdef CONFIG_PM
- .suspend = ufshcd_suspend,
- .resume = ufshcd_resume,
-#endif
-};
-
-module_pci_driver(ufshcd_pci_driver);
-
-MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>, "
- "Vinayak Holikatti <h.vinayak@samsung.com>");
-MODULE_DESCRIPTION("Generic UFS host controller driver");
+MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>");
+MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>");
+MODULE_DESCRIPTION("Generic UFS host controller driver Core");
MODULE_LICENSE("GPL");
MODULE_VERSION(UFSHCD_DRIVER_VERSION);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
new file mode 100644
index 0000000..6b99a42
--- /dev/null
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -0,0 +1,202 @@
+/*
+ * Universal Flash Storage Host controller driver
+ *
+ * This code is based on drivers/scsi/ufs/ufshcd.h
+ * Copyright (C) 2011-2013 Samsung India Software Operations
+ *
+ * Authors:
+ * Santosh Yaraganavi <santosh.sy@samsung.com>
+ * Vinayak Holikatti <h.vinayak@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * See the COPYING file in the top-level directory or visit
+ * <http://www.gnu.org/licenses/gpl-2.0.html>
+ *
+ * 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 program is provided "AS IS" and "WITH ALL FAULTS" and
+ * without warranty of any kind. You are solely responsible for
+ * determining the appropriateness of using and distributing
+ * the program and assume all risks associated with your exercise
+ * of rights with respect to the program, including but not limited
+ * to infringement of third party rights, the risks and costs of
+ * program errors, damage to or loss of data, programs or equipment,
+ * and unavailability or interruption of operations. Under no
+ * circumstances will the contributor of this Program be liable for
+ * any damages of any kind arising from your use or distribution of
+ * this program.
+ */
+
+#ifndef _UFSHCD_H
+#define _UFSHCD_H
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_eh.h>
+
+#include "ufs.h"
+#include "ufshci.h"
+
+#define UFSHCD "ufshcd"
+#define UFSHCD_DRIVER_VERSION "0.2"
+
+/**
+ * struct uic_command - UIC command structure
+ * @command: UIC command
+ * @argument1: UIC command argument 1
+ * @argument2: UIC command argument 2
+ * @argument3: UIC command argument 3
+ * @cmd_active: Indicate if UIC command is outstanding
+ * @result: UIC command result
+ */
+struct uic_command {
+ u32 command;
+ u32 argument1;
+ u32 argument2;
+ u32 argument3;
+ int cmd_active;
+ int result;
+};
+
+/**
+ * struct ufshcd_lrb - local reference block
+ * @utr_descriptor_ptr: UTRD address of the command
+ * @ucd_cmd_ptr: UCD address of the command
+ * @ucd_rsp_ptr: Response UPIU address for this command
+ * @ucd_prdt_ptr: PRDT address of the command
+ * @cmd: pointer to SCSI command
+ * @sense_buffer: pointer to sense buffer address of the SCSI command
+ * @sense_bufflen: Length of the sense buffer
+ * @scsi_status: SCSI status of the command
+ * @command_type: SCSI, UFS, Query.
+ * @task_tag: Task tag of the command
+ * @lun: LUN of the command
+ */
+struct ufshcd_lrb {
+ struct utp_transfer_req_desc *utr_descriptor_ptr;
+ struct utp_upiu_cmd *ucd_cmd_ptr;
+ struct utp_upiu_rsp *ucd_rsp_ptr;
+ struct ufshcd_sg_entry *ucd_prdt_ptr;
+
+ struct scsi_cmnd *cmd;
+ u8 *sense_buffer;
+ unsigned int sense_bufflen;
+ int scsi_status;
+
+ int command_type;
+ int task_tag;
+ unsigned int lun;
+};
+
+
+/**
+ * struct ufs_hba - per adapter private structure
+ * @mmio_base: UFSHCI base register address
+ * @ucdl_base_addr: UFS Command Descriptor base address
+ * @utrdl_base_addr: UTP Transfer Request Descriptor base address
+ * @utmrdl_base_addr: UTP Task Management Descriptor base address
+ * @ucdl_dma_addr: UFS Command Descriptor DMA address
+ * @utrdl_dma_addr: UTRDL DMA address
+ * @utmrdl_dma_addr: UTMRDL DMA address
+ * @host: Scsi_Host instance of the driver
+ * @dev: device handle
+ * @lrb: local reference block
+ * @outstanding_tasks: Bits representing outstanding task requests
+ * @outstanding_reqs: Bits representing outstanding transfer requests
+ * @capabilities: UFS Controller Capabilities
+ * @nutrs: Transfer Request Queue depth supported by controller
+ * @nutmrs: Task Management Queue depth supported by controller
+ * @ufs_version: UFS Version to which controller complies
+ * @irq: Irq number of the controller
+ * @active_uic_cmd: handle of active UIC command
+ * @ufshcd_tm_wait_queue: wait queue for task management
+ * @tm_condition: condition variable for task management
+ * @ufshcd_state: UFSHCD states
+ * @int_enable_mask: Interrupt Mask Bits
+ * @uic_workq: Work queue for UIC completion handling
+ * @feh_workq: Work queue for fatal controller error handling
+ * @errors: HBA errors
+ */
+struct ufs_hba {
+ void __iomem *mmio_base;
+
+ /* Virtual memory reference */
+ struct utp_transfer_cmd_desc *ucdl_base_addr;
+ struct utp_transfer_req_desc *utrdl_base_addr;
+ struct utp_task_req_desc *utmrdl_base_addr;
+
+ /* DMA memory reference */
+ dma_addr_t ucdl_dma_addr;
+ dma_addr_t utrdl_dma_addr;
+ dma_addr_t utmrdl_dma_addr;
+
+ struct Scsi_Host *host;
+ struct device *dev;
+
+ struct ufshcd_lrb *lrb;
+
+ unsigned long outstanding_tasks;
+ unsigned long outstanding_reqs;
+
+ u32 capabilities;
+ int nutrs;
+ int nutmrs;
+ u32 ufs_version;
+ unsigned int irq;
+
+ struct uic_command active_uic_cmd;
+ wait_queue_head_t ufshcd_tm_wait_queue;
+ unsigned long tm_condition;
+
+ u32 ufshcd_state;
+ u32 int_enable_mask;
+
+ /* Work Queues */
+ struct work_struct uic_workq;
+ struct work_struct feh_workq;
+
+ /* HBA Errors */
+ u32 errors;
+};
+
+int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * ,
+ unsigned int);
+void ufshcd_remove(struct ufs_hba *);
+
+/**
+ * ufshcd_hba_stop - Send controller to reset state
+ * @hba: per adapter instance
+ */
+static inline void ufshcd_hba_stop(struct ufs_hba *hba)
+{
+ writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
+}
+
+#endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index 6e3510f..0c16484 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -2,45 +2,35 @@
* Universal Flash Storage Host controller driver
*
* This code is based on drivers/scsi/ufs/ufshci.h
- * Copyright (C) 2011-2012 Samsung India Software Operations
+ * Copyright (C) 2011-2013 Samsung India Software Operations
*
- * Santosh Yaraganavi <santosh.sy@samsung.com>
- * Vinayak Holikatti <h.vinayak@samsung.com>
+ * Authors:
+ * Santosh Yaraganavi <santosh.sy@samsung.com>
+ * Vinayak Holikatti <h.vinayak@samsung.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
+ * See the COPYING file in the top-level directory or visit
+ * <http://www.gnu.org/licenses/gpl-2.0.html>
*
* 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.
*
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * This program is provided "AS IS" and "WITH ALL FAULTS" and
+ * without warranty of any kind. You are solely responsible for
+ * determining the appropriateness of using and distributing
+ * the program and assume all risks associated with your exercise
+ * of rights with respect to the program, including but not limited
+ * to infringement of third party rights, the risks and costs of
+ * program errors, damage to or loss of data, programs or equipment,
+ * and unavailability or interruption of operations. Under no
+ * circumstances will the contributor of this Program be liable for
+ * any damages of any kind arising from your use or distribution of
+ * this program.
*/
#ifndef _UFSHCI_H
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 7f60128..b89f608 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2013, 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
@@ -276,13 +276,12 @@
if (dd->input_block_size == 4 || dd->output_block_size == 4)
dd->use_dma = 0;
- /* DM mode is currently unsupported for different block sizes */
- if (dd->input_block_size != dd->output_block_size)
- dd->use_dma = 0;
-
- if (dd->use_dma)
- dd->burst_size = max(dd->input_block_size,
- DM_BURST_SIZE);
+ if (dd->use_dma) {
+ dd->input_burst_size = max(dd->input_block_size,
+ DM_BURST_SIZE);
+ dd->output_burst_size = max(dd->output_block_size,
+ DM_BURST_SIZE);
+ }
}
return;
@@ -646,7 +645,8 @@
static void msm_spi_setup_dm_transfer(struct msm_spi *dd)
{
dmov_box *box;
- int bytes_to_send, num_rows, bytes_sent;
+ int bytes_to_send, bytes_sent;
+ int tx_num_rows, rx_num_rows;
u32 num_transfers;
atomic_set(&dd->rx_irq_called, 0);
@@ -678,64 +678,80 @@
dd->max_trfr_len);
num_transfers = DIV_ROUND_UP(bytes_to_send, dd->bytes_per_word);
- dd->unaligned_len = bytes_to_send % dd->burst_size;
- num_rows = bytes_to_send / dd->burst_size;
+ dd->tx_unaligned_len = bytes_to_send % dd->output_burst_size;
+ dd->rx_unaligned_len = bytes_to_send % dd->input_burst_size;
+ tx_num_rows = bytes_to_send / dd->output_burst_size;
+ rx_num_rows = bytes_to_send / dd->input_burst_size;
dd->mode = SPI_DMOV_MODE;
- if (num_rows) {
+ if (tx_num_rows) {
/* src in 16 MSB, dst in 16 LSB */
box = &dd->tx_dmov_cmd->box;
box->src_row_addr = dd->cur_transfer->tx_dma + bytes_sent;
- box->src_dst_len = (dd->burst_size << 16) | dd->burst_size;
- box->num_rows = (num_rows << 16) | num_rows;
- box->row_offset = (dd->burst_size << 16) | 0;
+ box->src_dst_len
+ = (dd->output_burst_size << 16) | dd->output_burst_size;
+ box->num_rows = (tx_num_rows << 16) | tx_num_rows;
+ box->row_offset = (dd->output_burst_size << 16) | 0;
+ dd->tx_dmov_cmd->cmd_ptr = CMD_PTR_LP |
+ DMOV_CMD_ADDR(dd->tx_dmov_cmd_dma +
+ offsetof(struct spi_dmov_cmd, box));
+ } else {
+ dd->tx_dmov_cmd->cmd_ptr = CMD_PTR_LP |
+ DMOV_CMD_ADDR(dd->tx_dmov_cmd_dma +
+ offsetof(struct spi_dmov_cmd, single_pad));
+ }
+
+ if (rx_num_rows) {
+ /* src in 16 MSB, dst in 16 LSB */
box = &dd->rx_dmov_cmd->box;
box->dst_row_addr = dd->cur_transfer->rx_dma + bytes_sent;
- box->src_dst_len = (dd->burst_size << 16) | dd->burst_size;
- box->num_rows = (num_rows << 16) | num_rows;
- box->row_offset = (0 << 16) | dd->burst_size;
+ box->src_dst_len
+ = (dd->input_burst_size << 16) | dd->input_burst_size;
+ box->num_rows = (rx_num_rows << 16) | rx_num_rows;
+ box->row_offset = (0 << 16) | dd->input_burst_size;
- dd->tx_dmov_cmd->cmd_ptr = CMD_PTR_LP |
- DMOV_CMD_ADDR(dd->tx_dmov_cmd_dma +
- offsetof(struct spi_dmov_cmd, box));
dd->rx_dmov_cmd->cmd_ptr = CMD_PTR_LP |
DMOV_CMD_ADDR(dd->rx_dmov_cmd_dma +
offsetof(struct spi_dmov_cmd, box));
} else {
- dd->tx_dmov_cmd->cmd_ptr = CMD_PTR_LP |
- DMOV_CMD_ADDR(dd->tx_dmov_cmd_dma +
- offsetof(struct spi_dmov_cmd, single_pad));
dd->rx_dmov_cmd->cmd_ptr = CMD_PTR_LP |
DMOV_CMD_ADDR(dd->rx_dmov_cmd_dma +
offsetof(struct spi_dmov_cmd, single_pad));
}
- if (!dd->unaligned_len) {
+ if (!dd->tx_unaligned_len) {
dd->tx_dmov_cmd->box.cmd |= CMD_LC;
- dd->rx_dmov_cmd->box.cmd |= CMD_LC;
} else {
dmov_s *tx_cmd = &(dd->tx_dmov_cmd->single_pad);
- dmov_s *rx_cmd = &(dd->rx_dmov_cmd->single_pad);
- u32 offset = dd->cur_transfer->len - dd->unaligned_len;
+ u32 tx_offset = dd->cur_transfer->len - dd->tx_unaligned_len;
if ((dd->multi_xfr) && (dd->read_len <= 0))
- offset = dd->cur_msg_len - dd->unaligned_len;
+ tx_offset = dd->cur_msg_len - dd->tx_unaligned_len;
dd->tx_dmov_cmd->box.cmd &= ~CMD_LC;
- dd->rx_dmov_cmd->box.cmd &= ~CMD_LC;
- memset(dd->tx_padding, 0, dd->burst_size);
- memset(dd->rx_padding, 0, dd->burst_size);
+ memset(dd->tx_padding, 0, dd->output_burst_size);
if (dd->write_buf)
- memcpy(dd->tx_padding, dd->write_buf + offset,
- dd->unaligned_len);
+ memcpy(dd->tx_padding, dd->write_buf + tx_offset,
+ dd->tx_unaligned_len);
tx_cmd->src = dd->tx_padding_dma;
- rx_cmd->dst = dd->rx_padding_dma;
- tx_cmd->len = rx_cmd->len = dd->burst_size;
+ tx_cmd->len = dd->output_burst_size;
}
+
+ if (!dd->rx_unaligned_len) {
+ dd->rx_dmov_cmd->box.cmd |= CMD_LC;
+ } else {
+ dmov_s *rx_cmd = &(dd->rx_dmov_cmd->single_pad);
+ dd->rx_dmov_cmd->box.cmd &= ~CMD_LC;
+
+ memset(dd->rx_padding, 0, dd->input_burst_size);
+ rx_cmd->dst = dd->rx_padding_dma;
+ rx_cmd->len = dd->input_burst_size;
+ }
+
/* This also takes care of the padding dummy buf
Since this is set to the correct length, the
dummy bytes won't be actually sent */
@@ -893,7 +909,7 @@
if ((!dd->read_buf || op & SPI_OP_MAX_INPUT_DONE_FLAG) &&
(!dd->write_buf || op & SPI_OP_MAX_OUTPUT_DONE_FLAG)) {
msm_spi_ack_transfer(dd);
- if (dd->unaligned_len == 0) {
+ if (dd->rx_unaligned_len == 0) {
if (atomic_inc_return(&dd->rx_irq_called) == 1)
return IRQ_HANDLED;
}
@@ -1145,11 +1161,11 @@
prev_xfr->len,
DMA_TO_DEVICE);
}
- if (dd->unaligned_len && dd->read_buf) {
- offset = dd->cur_msg_len - dd->unaligned_len;
+ if (dd->rx_unaligned_len && dd->read_buf) {
+ offset = dd->cur_msg_len - dd->rx_unaligned_len;
dma_coherent_post_ops();
memcpy(dd->read_buf + offset, dd->rx_padding,
- dd->unaligned_len);
+ dd->rx_unaligned_len);
memcpy(dd->cur_transfer->rx_buf,
dd->read_buf + prev_xfr->len,
dd->cur_transfer->len);
@@ -1171,11 +1187,11 @@
unmap_end:
/* If we padded the transfer, we copy it from the padding buf */
- if (dd->unaligned_len && dd->read_buf) {
- offset = dd->cur_transfer->len - dd->unaligned_len;
+ if (dd->rx_unaligned_len && dd->read_buf) {
+ offset = dd->cur_transfer->len - dd->rx_unaligned_len;
dma_coherent_post_ops();
memcpy(dd->read_buf + offset, dd->rx_padding,
- dd->unaligned_len);
+ dd->rx_unaligned_len);
}
}
@@ -1960,7 +1976,8 @@
"use_dma ? %s\n"
"rx block size = %d bytes\n"
"tx block size = %d bytes\n"
- "burst size = %d bytes\n"
+ "input burst size = %d bytes\n"
+ "output burst size = %d bytes\n"
"DMA configuration:\n"
"tx_ch=%d, rx_ch=%d, tx_crci= %d, rx_crci=%d\n"
"--statistics--\n"
@@ -1975,7 +1992,8 @@
dd->use_dma ? "yes" : "no",
dd->input_block_size,
dd->output_block_size,
- dd->burst_size,
+ dd->input_burst_size,
+ dd->output_burst_size,
dd->tx_dma_chan,
dd->rx_dma_chan,
dd->tx_dma_crci,
@@ -2104,12 +2122,15 @@
}
}
-static inline u32 get_chunk_size(struct msm_spi *dd)
+static inline u32 get_chunk_size(struct msm_spi *dd, int input_burst_size,
+ int output_burst_size)
{
u32 cache_line = dma_get_cache_alignment();
+ int burst_size = (input_burst_size > output_burst_size) ?
+ input_burst_size : output_burst_size;
return (roundup(sizeof(struct spi_dmov_cmd), DM_BYTE_ALIGN) +
- roundup(dd->burst_size, cache_line))*2;
+ roundup(burst_size, cache_line))*2;
}
static void msm_spi_dmov_teardown(struct msm_spi *dd)
@@ -2125,8 +2146,10 @@
msleep(10);
}
- dma_free_coherent(NULL, get_chunk_size(dd), dd->tx_dmov_cmd,
- dd->tx_dmov_cmd_dma);
+ dma_free_coherent(NULL,
+ get_chunk_size(dd, dd->input_burst_size, dd->output_burst_size),
+ dd->tx_dmov_cmd,
+ dd->tx_dmov_cmd_dma);
dd->tx_dmov_cmd = dd->rx_dmov_cmd = NULL;
dd->tx_padding = dd->rx_padding = NULL;
}
@@ -2304,8 +2327,11 @@
/* We send NULL device, since it requires coherent_dma_mask id
device definition, we're okay with using system pool */
- dd->tx_dmov_cmd = dma_alloc_coherent(NULL, get_chunk_size(dd),
- &dd->tx_dmov_cmd_dma, GFP_KERNEL);
+ dd->tx_dmov_cmd
+ = dma_alloc_coherent(NULL,
+ get_chunk_size(dd, dd->input_burst_size,
+ dd->output_burst_size),
+ &dd->tx_dmov_cmd_dma, GFP_KERNEL);
if (dd->tx_dmov_cmd == NULL)
return -ENOMEM;
@@ -2319,9 +2345,9 @@
dd->tx_padding = (u8 *)ALIGN((size_t)&dd->rx_dmov_cmd[1], cache_line);
dd->tx_padding_dma = ALIGN(dd->rx_dmov_cmd_dma +
sizeof(struct spi_dmov_cmd), cache_line);
- dd->rx_padding = (u8 *)ALIGN((size_t)(dd->tx_padding + dd->burst_size),
- cache_line);
- dd->rx_padding_dma = ALIGN(dd->tx_padding_dma + dd->burst_size,
+ dd->rx_padding = (u8 *)ALIGN((size_t)(dd->tx_padding +
+ dd->output_burst_size), cache_line);
+ dd->rx_padding_dma = ALIGN(dd->tx_padding_dma + dd->output_burst_size,
cache_line);
/* Setup DM commands */
diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h
index 7f5b726..b749cc0 100644
--- a/drivers/spi/spi_qsd.h
+++ b/drivers/spi/spi_qsd.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2013, 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
@@ -318,7 +318,8 @@
struct msm_dmov_cmd rx_hdr;
int input_block_size;
int output_block_size;
- int burst_size;
+ int input_burst_size;
+ int output_burst_size;
atomic_t rx_irq_called;
atomic_t tx_irq_called;
/* Used to pad messages unaligned to block size */
@@ -326,7 +327,8 @@
dma_addr_t tx_padding_dma;
u8 *rx_padding;
dma_addr_t rx_padding_dma;
- u32 unaligned_len;
+ u32 tx_unaligned_len;
+ u32 rx_unaligned_len;
/* DMA statistics */
int stat_dmov_tx_err;
int stat_dmov_rx_err;
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
index 0348145..8760603 100644
--- a/drivers/tty/n_smux.c
+++ b/drivers/tty/n_smux.c
@@ -1719,7 +1719,7 @@
*/
static int smux_handle_rx_power_cmd(struct smux_pkt_t *pkt)
{
- struct smux_pkt_t *ack_pkt = NULL;
+ struct smux_pkt_t *ack_pkt;
int power_down = 0;
unsigned long flags;
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index c982587..65e4989 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -218,6 +218,7 @@
u32 bus_perf_client;
/* BLSP UART required BUS Scaling data */
struct msm_bus_scale_pdata *bus_scale_table;
+ bool rx_discard_flush_issued;
};
#define MSM_UARTDM_BURST_SIZE 16 /* DM burst size (in bytes) */
@@ -229,6 +230,7 @@
#define BAM_PIPE_MAX 11
#define BUS_SCALING 1
#define BUS_RESET 0
+#define RX_FLUSH_COMPLETE_TIMEOUT 300 /* In jiffies */
static struct dentry *debug_base;
static struct msm_hs_port q_uart_port[UARTDM_NR];
@@ -849,6 +851,7 @@
{
unsigned int bps;
unsigned long data;
+ int ret;
unsigned int c_cflag = termios->c_cflag;
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
struct msm_hs_rx *rx = &msm_uport->rx;
@@ -969,8 +972,17 @@
msm_hs_spsconnect_rx(uport);
msm_serial_hs_rx_tlet((unsigned long) &rx->tlet);
} else {
+ msm_uport->rx_discard_flush_issued = true;
/* do discard flush */
msm_dmov_flush(msm_uport->dma_rx_channel, 0);
+ pr_debug("%s(): wainting for flush completion.\n",
+ __func__);
+ ret = wait_event_timeout(msm_uport->rx.wait,
+ msm_uport->rx_discard_flush_issued == false,
+ RX_FLUSH_COMPLETE_TIMEOUT);
+ if (!ret)
+ pr_err("%s(): Discard flush pending.\n",
+ __func__);
}
}
@@ -1514,8 +1526,23 @@
struct msm_dmov_errdata *err)
{
struct msm_hs_port *msm_uport;
+ struct uart_port *uport;
+ unsigned long flags;
msm_uport = container_of(cmd_ptr, struct msm_hs_port, rx.xfer);
+ uport = &(msm_uport->uport);
+
+ pr_debug("%s(): called result:%x\n", __func__, result);
+ if (!(result & DMOV_RSLT_ERROR)) {
+ if (result & DMOV_RSLT_FLUSH) {
+ if (msm_uport->rx_discard_flush_issued) {
+ spin_lock_irqsave(&uport->lock, flags);
+ msm_uport->rx_discard_flush_issued = false;
+ spin_unlock_irqrestore(&uport->lock, flags);
+ wake_up(&msm_uport->rx.wait);
+ }
+ }
+ }
tasklet_schedule(&msm_uport->rx.tlet);
}
@@ -1661,6 +1688,7 @@
{
unsigned long sr_status;
unsigned long flags;
+ int ret;
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
struct circ_buf *tx_buf = &uport->state->xmit;
@@ -1716,10 +1744,23 @@
}
if (msm_uport->rx.flush != FLUSH_SHUTDOWN) {
- if (msm_uport->rx.flush == FLUSH_NONE)
+ if (msm_uport->rx.flush == FLUSH_NONE) {
msm_hs_stop_rx_locked(uport);
+ msm_uport->rx_discard_flush_issued = true;
+ }
spin_unlock_irqrestore(&uport->lock, flags);
+ if (msm_uport->rx_discard_flush_issued) {
+ pr_debug("%s(): wainting for flush completion.\n",
+ __func__);
+ ret = wait_event_timeout(msm_uport->rx.wait,
+ msm_uport->rx_discard_flush_issued == false,
+ RX_FLUSH_COMPLETE_TIMEOUT);
+ if (!ret)
+ pr_err("%s(): Flush complete pending.\n",
+ __func__);
+ }
+
mutex_unlock(&msm_uport->clk_mutex);
return 0; /* come back later to really clock off */
}
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 9dd9c40..87a0078 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -516,6 +516,82 @@
/*-------------------------------------------------------------------------*/
/* Supported functions initialization */
+/* ACM */
+static char acm_transports[32]; /*enabled ACM ports - "tty[,sdio]"*/
+static ssize_t acm_transports_store(
+ struct device *device, struct device_attribute *attr,
+ const char *buff, size_t size)
+{
+ strlcpy(acm_transports, buff, sizeof(acm_transports));
+
+ return size;
+}
+
+static DEVICE_ATTR(acm_transports, S_IWUSR, NULL, acm_transports_store);
+static struct device_attribute *acm_function_attributes[] = {
+ &dev_attr_acm_transports,
+ NULL
+};
+
+static void acm_function_cleanup(struct android_usb_function *f)
+{
+ gserial_cleanup();
+}
+
+static int
+acm_function_bind_config(struct android_usb_function *f,
+ struct usb_configuration *c)
+{
+ char *name;
+ char buf[32], *b;
+ int err = -1, i;
+ static int acm_initialized, ports;
+
+ if (acm_initialized)
+ goto bind_config;
+
+ acm_initialized = 1;
+ strlcpy(buf, acm_transports, sizeof(buf));
+ b = strim(buf);
+
+ while (b) {
+ name = strsep(&b, ",");
+
+ if (name) {
+ err = acm_init_port(ports, name);
+ if (err) {
+ pr_err("acm: Cannot open port '%s'", name);
+ goto out;
+ }
+ ports++;
+ }
+ }
+ err = acm_port_setup(c);
+ if (err) {
+ pr_err("acm: Cannot setup transports");
+ goto out;
+ }
+
+bind_config:
+ for (i = 0; i < ports; i++) {
+ err = acm_bind_config(c, i);
+ if (err) {
+ pr_err("acm: bind_config failed for port %d", i);
+ goto out;
+ }
+ }
+
+out:
+ return err;
+}
+
+static struct android_usb_function acm_function = {
+ .name = "acm",
+ .cleanup = acm_function_cleanup,
+ .bind_config = acm_function_bind_config,
+ .attributes = acm_function_attributes,
+};
+
/* RMNET_SMD */
static int rmnet_smd_function_bind_config(struct android_usb_function *f,
struct usb_configuration *c)
@@ -996,78 +1072,6 @@
.attributes = serial_function_attributes,
};
-/* ACM */
-static char acm_transports[32]; /*enabled ACM ports - "tty[,sdio]"*/
-static ssize_t acm_transports_store(
- struct device *device, struct device_attribute *attr,
- const char *buff, size_t size)
-{
- strlcpy(acm_transports, buff, sizeof(acm_transports));
-
- return size;
-}
-
-static DEVICE_ATTR(acm_transports, S_IWUSR, NULL, acm_transports_store);
-static struct device_attribute *acm_function_attributes[] = {
- &dev_attr_acm_transports, NULL };
-
-static void acm_function_cleanup(struct android_usb_function *f)
-{
- gserial_cleanup();
-}
-
-static int acm_function_bind_config(struct android_usb_function *f,
- struct usb_configuration *c)
-{
- char *name;
- char buf[32], *b;
- int err = -1, i;
- static int acm_initialized, ports;
-
- if (acm_initialized)
- goto bind_config;
-
- acm_initialized = 1;
- strlcpy(buf, acm_transports, sizeof(buf));
- b = strim(buf);
-
- while (b) {
- name = strsep(&b, ",");
-
- if (name) {
- err = acm_init_port(ports, name);
- if (err) {
- pr_err("acm: Cannot open port '%s'", name);
- goto out;
- }
- ports++;
- }
- }
- err = acm_port_setup(c);
- if (err) {
- pr_err("acm: Cannot setup transports");
- goto out;
- }
-
-bind_config:
- for (i = 0; i < ports; i++) {
- err = acm_bind_config(c, i);
- if (err) {
- pr_err("acm: bind_config failed for port %d", i);
- goto out;
- }
- }
-
-out:
- return err;
-}
-static struct android_usb_function acm_function = {
- .name = "acm",
- .cleanup = acm_function_cleanup,
- .bind_config = acm_function_bind_config,
- .attributes = acm_function_attributes,
-};
-
/* CCID */
static int ccid_function_init(struct android_usb_function *f,
struct usb_composite_dev *cdev)
@@ -1093,7 +1097,8 @@
.bind_config = ccid_function_bind_config,
};
-static int mtp_function_init(struct android_usb_function *f,
+static int
+mtp_function_init(struct android_usb_function *f,
struct usb_composite_dev *cdev)
{
return mtp_setup();
@@ -1104,13 +1109,16 @@
mtp_cleanup();
}
-static int mtp_function_bind_config(struct android_usb_function *f,
+static int
+mtp_function_bind_config(struct android_usb_function *f,
struct usb_configuration *c)
{
return mtp_bind_config(c, false);
}
-static int ptp_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev)
+static int
+ptp_function_init(struct android_usb_function *f,
+ struct usb_composite_dev *cdev)
{
/* nothing to do - initialization is handled by mtp_function_init */
return 0;
@@ -1121,7 +1129,9 @@
/* nothing to do - cleanup is handled by mtp_function_cleanup */
}
-static int ptp_function_bind_config(struct android_usb_function *f, struct usb_configuration *c)
+static int
+ptp_function_bind_config(struct android_usb_function *f,
+ struct usb_configuration *c)
{
return mtp_bind_config(c, true);
}
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index c02c8e4..81fc1cc 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -1391,9 +1391,6 @@
dev_err(dev, "[%s] EINVAL\n", __func__);
return 0;
}
- dump = kmalloc(2048, GFP_KERNEL);
- if (dump == NULL)
- return -ENOMEM;
dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
if (!dump) {
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 4bc0da2..de4a233 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -176,13 +176,12 @@
_ep->comp_desc = comp_desc;
if (g->speed == USB_SPEED_SUPER) {
switch (usb_endpoint_type(_ep->desc)) {
- case USB_ENDPOINT_XFER_BULK:
- case USB_ENDPOINT_XFER_INT:
- _ep->maxburst = comp_desc->bMaxBurst + 1;
- break;
case USB_ENDPOINT_XFER_ISOC:
/* mult: bits 1:0 of bmAttributes */
_ep->mult = comp_desc->bmAttributes & 0x3;
+ case USB_ENDPOINT_XFER_BULK:
+ case USB_ENDPOINT_XFER_INT:
+ _ep->maxburst = comp_desc->bMaxBurst + 1;
break;
default:
if (comp_desc->bMaxBurst != 0)
@@ -693,7 +692,6 @@
CONFIG_USB_GADGET_VBUS_DRAW;
done:
usb_gadget_vbus_draw(gadget, power);
-
if (result >= 0 && cdev->delayed_status)
result = USB_GADGET_DELAYED_STATUS;
return result;
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index 0752188..de54714 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -18,7 +18,6 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/device.h>
-#include <linux/usb/android_composite.h>
#include <mach/usb_gadget_xport.h>
#include "u_serial.h"
diff --git a/drivers/usb/gadget/f_ccid.c b/drivers/usb/gadget/f_ccid.c
index 4e28d34..6888935 100644
--- a/drivers/usb/gadget/f_ccid.c
+++ b/drivers/usb/gadget/f_ccid.c
@@ -16,7 +16,6 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/device.h>
-#include <linux/usb/android_composite.h>
#include <linux/fs.h>
#include <linux/usb/ccid_desc.h>
#include <linux/miscdevice.h>
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 245a972..bac8b68 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -3200,7 +3200,7 @@
if (unlikely(!fsg))
return -ENOMEM;
- fsg->function.name = "mass_storage";
+ fsg->function.name = FSG_DRIVER_DESC;
fsg->function.strings = fsg_strings_array;
fsg->function.bind = fsg_bind;
fsg->function.unbind = fsg_unbind;
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 0d8fa0f..af68827 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -14,7 +14,6 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/device.h>
-#include <linux/usb/android_composite.h>
#include <linux/spinlock.h>
#include <mach/usb_gadget_xport.h>
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index c71685d..502c33a 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -448,6 +448,8 @@
prev_len = req->length;
port->nbytes_from_tty += req->length;
+ port->write_started++;
+
}
if (do_tty_wake && port->port_tty)
@@ -1381,7 +1383,6 @@
/* export the driver ... */
status = tty_register_driver(gs_tty_driver);
if (status) {
- put_tty_driver(gs_tty_driver);
pr_err("%s: cannot register, err %d\n",
__func__, status);
goto fail;
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index ea5484b..8c0894c 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -49,6 +49,7 @@
#include <linux/spinlock.h>
#include <linux/cpu.h>
#include <mach/rpm-regulator.h>
+#include "hbm.c"
#define MSM_USB_BASE (hcd->regs)
#define USB_REG_START_OFFSET 0x90
@@ -105,6 +106,7 @@
int reset_again;
struct pm_qos_request pm_qos_req_dma;
+ unsigned enable_hbm:1;
};
struct msm_hsic_hcd *__mehci;
@@ -1367,6 +1369,18 @@
pm_runtime_set_autosuspend_delay(&dev->dev, 200);
}
+static int ehci_msm_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+ struct usb_host_bam_type *usb_host_bam =
+ (struct usb_host_bam_type *)urb->priv_data;
+
+ if (usb_host_bam && mehci && mehci->enable_hbm)
+ return hbm_urb_enqueue(hcd, urb, mem_flags);
+ return ehci_urb_enqueue(hcd, urb, mem_flags);
+}
+
static struct hc_driver msm_hsic_driver = {
.description = hcd_name,
.product_desc = "Qualcomm EHCI Host Controller using HSIC",
@@ -1387,7 +1401,7 @@
/*
* managing i/o requests and associated device resources
*/
- .urb_enqueue = ehci_urb_enqueue,
+ .urb_enqueue = ehci_msm_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
.endpoint_reset = ehci_endpoint_reset,
@@ -1778,6 +1792,8 @@
pdata->pool_64_bit_align = of_property_read_bool(node,
"qcom,pool-64-bit-align");
+ pdata->enable_hbm = of_property_read_bool(node,
+ "qcom,enable-hbm");
return pdata;
}
@@ -1789,6 +1805,7 @@
struct resource *res;
struct msm_hsic_hcd *mehci;
struct msm_hsic_host_platform_data *pdata;
+ unsigned long wakeup_irq_flags = 0;
int ret;
dev_dbg(&pdev->dev, "ehci_msm-hsic probe\n");
@@ -1797,6 +1814,9 @@
dev_dbg(&pdev->dev, "device tree enabled\n");
pdev->dev.platform_data = msm_hsic_dt_to_pdata(pdev);
dev_set_name(&pdev->dev, ehci_msm_hsic_driver.driver.name);
+ } else {
+ /* explicitly pass wakeup_irq flag for !DT */
+ wakeup_irq_flags = IRQF_TRIGGER_HIGH;
}
if (!pdev->dev.platform_data)
dev_dbg(&pdev->dev, "No platform data given\n");
@@ -1857,6 +1877,7 @@
mehci->ehci.resume_sof_bug = 1;
mehci->ehci.pool_64_bit_align = pdata->pool_64_bit_align;
+ mehci->enable_hbm = pdata->enable_hbm;
if (pdata)
mehci->ehci.log2_irq_thresh = pdata->log2_irq_thresh;
@@ -1944,7 +1965,7 @@
*/
irq_set_status_flags(mehci->wakeup_irq, IRQ_NOAUTOEN);
ret = request_irq(mehci->wakeup_irq, msm_hsic_wakeup_irq,
- IRQF_TRIGGER_HIGH,
+ wakeup_irq_flags,
"msm_hsic_wakeup", mehci);
if (ret) {
dev_err(&pdev->dev, "request_irq(%d) failed: %d\n",
@@ -1963,7 +1984,8 @@
if (ret) {
dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n");
mehci->async_irq = 0;
- } else {
+ } else if (!mehci->wakeup_irq) {
+ /* Async IRQ is used only in absence of dedicated irq */
enable_irq_wake(mehci->async_irq);
}
}
@@ -2006,6 +2028,9 @@
if (pdev->dev.parent)
pm_runtime_put_sync(pdev->dev.parent);
+ if (mehci->enable_hbm)
+ hbm_init(hcd);
+
return 0;
destroy_wq:
@@ -2035,6 +2060,9 @@
pm_runtime_set_suspended(&pdev->dev);
+ if (mehci->enable_hbm)
+ hbm_uninit();
+
/* Remove the HCD prior to releasing our resources. */
usb_remove_hcd(hcd);
@@ -2093,12 +2121,12 @@
dbg_log_event(NULL, "PM Suspend", 0);
- if (device_may_wakeup(dev))
+ if (device_may_wakeup(dev) && !mehci->async_irq)
enable_irq_wake(hcd->irq);
ret = msm_hsic_suspend(mehci);
- if (ret && device_may_wakeup(dev))
+ if (ret && device_may_wakeup(dev) && !mehci->async_irq)
disable_irq_wake(hcd->irq);
return ret;
@@ -2126,7 +2154,7 @@
dev_dbg(dev, "ehci-msm-hsic PM resume\n");
dbg_log_event(NULL, "PM Resume", 0);
- if (device_may_wakeup(dev))
+ if (device_may_wakeup(dev) && !mehci->async_irq)
disable_irq_wake(hcd->irq);
/*
diff --git a/drivers/usb/host/hbm.c b/drivers/usb/host/hbm.c
index f516ad8..d48a631 100644
--- a/drivers/usb/host/hbm.c
+++ b/drivers/usb/host/hbm.c
@@ -194,12 +194,6 @@
pr_err("%s: hbm_ctx alloc failed\n", __func__);
return;
}
- hbm_ctx->base = kzalloc(sizeof(u32), GFP_KERNEL);
- if (!hbm_ctx->base) {
- pr_err("%s: hbm_ctx base alloc failed\n", __func__);
- kfree(hbm_ctx);
- return;
- }
hbm_ctx->base = hcd->regs;
hbm_ctx->hcd = hcd;
@@ -214,7 +208,7 @@
void hbm_uninit(void)
{
- kfree(hbm_ctx->base);
+ hbm_config(false);
kfree(hbm_ctx);
}
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 1c7d928..7760d28 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -151,8 +151,8 @@
rc = regulator_set_voltage(hsusb_1p8, USB_PHY_1P8_VOL_MIN,
USB_PHY_1P8_VOL_MAX);
if (rc) {
- dev_err(motg->phy.dev, "unable to set voltage level for"
- "hsusb 1p8\n");
+ dev_err(motg->phy.dev, "unable to set voltage level "
+ "for hsusb 1p8\n");
goto put_1p8;
}
@@ -207,7 +207,7 @@
ret = regulator_set_optimum_mode(hsusb_1p8,
USB_PHY_1P8_HPM_LOAD);
if (ret < 0) {
- pr_err("%s: Unable to set HPM of the regulator:"
+ pr_err("%s: Unable to set HPM of the regulator "
"HSUSB_1p8\n", __func__);
return ret;
}
@@ -223,7 +223,7 @@
ret = regulator_set_optimum_mode(hsusb_3p3,
USB_PHY_3P3_HPM_LOAD);
if (ret < 0) {
- pr_err("%s: Unable to set HPM of the regulator:"
+ pr_err("%s: Unable to set HPM of the regulator "
"HSUSB_3p3\n", __func__);
regulator_set_optimum_mode(hsusb_1p8, 0);
regulator_disable(hsusb_1p8);
@@ -252,7 +252,7 @@
ret = regulator_set_optimum_mode(hsusb_1p8, 0);
if (ret < 0)
- pr_err("%s: Unable to set LPM of the regulator:"
+ pr_err("%s: Unable to set LPM of the regulator "
"HSUSB_1p8\n", __func__);
ret = regulator_disable(hsusb_3p3);
@@ -263,7 +263,7 @@
}
ret = regulator_set_optimum_mode(hsusb_3p3, 0);
if (ret < 0)
- pr_err("%s: Unable to set LPM of the regulator:"
+ pr_err("%s: Unable to set LPM of the regulator "
"HSUSB_3p3\n", __func__);
break;
@@ -1575,7 +1575,7 @@
}
static int msm_otg_set_peripheral(struct usb_otg *otg,
- struct usb_gadget *gadget)
+ struct usb_gadget *gadget)
{
struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
@@ -3017,10 +3017,10 @@
if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
if (otgsc & OTGSC_ID) {
- pr_debug("Id set\n");
+ dev_dbg(otg->phy->dev, "ID set\n");
set_bit(ID, &motg->inputs);
} else {
- pr_debug("Id clear\n");
+ dev_dbg(otg->phy->dev, "ID clear\n");
/*
* Assert a_bus_req to supply power on
* VBUS when Micro/Mini-A cable is connected
@@ -3049,10 +3049,10 @@
!test_bit(ID_A, &motg->inputs))
return IRQ_HANDLED;
if (otgsc & OTGSC_BSV) {
- pr_debug("BSV set\n");
+ dev_dbg(otg->phy->dev, "BSV set\n");
set_bit(B_SESS_VLD, &motg->inputs);
} else {
- pr_debug("BSV clear\n");
+ dev_dbg(otg->phy->dev, "BSV clear\n");
clear_bit(B_SESS_VLD, &motg->inputs);
clear_bit(A_BUS_SUSPEND, &motg->inputs);
@@ -3245,9 +3245,9 @@
static int msm_otg_mode_show(struct seq_file *s, void *unused)
{
struct msm_otg *motg = s->private;
- struct usb_phy *phy = &motg->phy;
+ struct usb_otg *otg = motg->phy.otg;
- switch (phy->state) {
+ switch (otg->phy->state) {
case OTG_STATE_A_HOST:
seq_printf(s, "host\n");
break;
@@ -4228,10 +4228,10 @@
static int __devexit msm_otg_remove(struct platform_device *pdev)
{
struct msm_otg *motg = platform_get_drvdata(pdev);
- struct usb_otg *otg = motg->phy.otg;
+ struct usb_phy *phy = &motg->phy;
int cnt = 0;
- if (otg->host || otg->gadget)
+ if (phy->otg->host || phy->otg->gadget)
return -EBUSY;
if (pdev->dev.of_node)
@@ -4264,8 +4264,8 @@
/*
* Put PHY in low power mode.
*/
- ulpi_read(otg->phy, 0x14);
- ulpi_write(otg->phy, 0x08, 0x09);
+ ulpi_read(phy, 0x14);
+ ulpi_write(phy, 0x08, 0x09);
writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
@@ -4275,7 +4275,7 @@
cnt++;
}
if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
- dev_err(otg->phy->dev, "Unable to suspend PHY\n");
+ dev_err(phy->dev, "Unable to suspend PHY\n");
clk_disable_unprepare(motg->pclk);
clk_disable_unprepare(motg->core_clk);
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index ed4c25d..1c59a68 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -10,6 +10,8 @@
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select SYNC
+ select SW_SYNC
---help---
Support for MSM Framebuffer.
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 99eea82..9c77445 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -659,7 +659,7 @@
return rc;
}
- if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 103300000))
+ if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 250000000))
dsi_pclk_rate = 35000000;
mipi->dsi_pclk_rate = dsi_pclk_rate;
@@ -718,7 +718,8 @@
pr_err("request reset gpio failed, rc=%d\n",
rc);
gpio_free(ctrl_pdata->rst_gpio);
- gpio_free(ctrl_pdata->disp_en_gpio);
+ if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+ gpio_free(ctrl_pdata->disp_en_gpio);
return -ENODEV;
}
}
@@ -782,7 +783,7 @@
devm_kfree(&pdev->dev, ctrl_pdata);
if (ctrl_pdata->rst_gpio)
gpio_free(ctrl_pdata->rst_gpio);
- if (ctrl_pdata->disp_en_gpio)
+ if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
gpio_free(ctrl_pdata->disp_en_gpio);
return rc;
}
@@ -790,6 +791,11 @@
ctrl_pdata->on = panel_data->on;
ctrl_pdata->off = panel_data->off;
+ ctrl_pdata->pclk_rate = dsi_pclk_rate;
+ ctrl_pdata->byte_clk_rate = panel_data->panel_info.clk_rate / 8;
+ pr_debug("%s: pclk=%d, bclk=%d\n", __func__,
+ ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate);
+
pr_debug("%s: Panal data initialized\n", __func__);
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 06c2952..4b920a6 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -286,6 +286,8 @@
struct dsi_panel_cmds_list *on_cmds;
struct dsi_panel_cmds_list *off_cmds;
struct dsi_drv_cm_data shared_pdata;
+ u32 pclk_rate;
+ u32 byte_clk_rate;
};
int dsi_panel_device_register(struct platform_device *pdev,
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 4c30d18..8d38737 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -45,7 +45,6 @@
if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
pr_debug("%s:%d, reset line not configured\n",
__func__, __LINE__);
- return;
}
if (!gpio_is_valid(ctrl_pdata->rst_gpio)) {
@@ -59,18 +58,16 @@
if (enable) {
gpio_set_value((ctrl_pdata->rst_gpio), 1);
msleep(20);
- wmb();
gpio_set_value((ctrl_pdata->rst_gpio), 0);
udelay(200);
- wmb();
gpio_set_value((ctrl_pdata->rst_gpio), 1);
msleep(20);
- wmb();
- gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
- wmb();
+ if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+ gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
} else {
gpio_set_value((ctrl_pdata->rst_gpio), 0);
- gpio_set_value((ctrl_pdata->disp_en_gpio), 0);
+ if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+ gpio_set_value((ctrl_pdata->disp_en_gpio), 0);
}
}
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 4f95aee..6c7a1195 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -1774,6 +1774,12 @@
return -ENODEV;
}
+ if (!hdmi_ctrl->audio_sdev.state) {
+ DEV_ERR("%s: failed. HDMI is not connected/ready for audio\n",
+ __func__);
+ return -EPERM;
+ }
+
return hdmi_edid_get_audio_blk(
hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID], blk);
} /* hdmi_tx_get_audio_edid_blk */
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index 30dd471..ccddf44 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -1712,18 +1712,18 @@
struct input_dev *input = mhl_ctrl->input;
mhl_ctrl->rcp_key_code_tbl = vmalloc(
- ARRAY_SIZE(support_rcp_key_code_tbl));
+ sizeof(support_rcp_key_code_tbl));
if (!mhl_ctrl->rcp_key_code_tbl) {
pr_err("%s: no alloc mem for rcp keycode tbl\n",
__func__);
return -ENOMEM;
}
+ mhl_ctrl->rcp_key_code_tbl_len = sizeof(
+ support_rcp_key_code_tbl);
memcpy(mhl_ctrl->rcp_key_code_tbl,
&support_rcp_key_code_tbl[0],
- ARRAY_SIZE(support_rcp_key_code_tbl));
- mhl_ctrl->rcp_key_code_tbl_len = ARRAY_SIZE(
- support_rcp_key_code_tbl);
+ mhl_ctrl->rcp_key_code_tbl_len);
input->phys = "cbus/input0";
input->id.bustype = BUS_VIRTUAL;
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 3b6fc38..2b07e43 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -173,6 +173,7 @@
void mdss_dsi_clk_enable(struct mdss_panel_data *pdata)
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ u32 esc_clk_rate = 19200000;
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
@@ -186,17 +187,17 @@
return;
}
- if (clk_set_rate(ctrl_pdata->esc_clk, 19200000) < 0)
- pr_err("%s: dsi_esc_clk - clk_set_rate failed\n",
- __func__);
+ pr_debug("%s: Setting clock rates: pclk=%d, byteclk=%d escclk=%d\n",
+ __func__, ctrl_pdata->pclk_rate,
+ ctrl_pdata->byte_clk_rate, esc_clk_rate);
+ if (clk_set_rate(ctrl_pdata->esc_clk, esc_clk_rate) < 0)
+ pr_err("%s: dsi_esc_clk - clk_set_rate failed\n", __func__);
- if (clk_set_rate(ctrl_pdata->byte_clk, 53000000) < 0)
- pr_err("%s: dsi_byte_clk - clk_set_rate failed\n",
- __func__);
+ if (clk_set_rate(ctrl_pdata->byte_clk, ctrl_pdata->byte_clk_rate) < 0)
+ pr_err("%s: dsi_byte_clk - clk_set_rate failed\n", __func__);
- if (clk_set_rate(ctrl_pdata->pixel_clk, 70000000) < 0)
- pr_err("%s: dsi_pixel_clk - clk_set_rate failed\n",
- __func__);
+ if (clk_set_rate(ctrl_pdata->pixel_clk, ctrl_pdata->pclk_rate) < 0)
+ pr_err("%s: dsi_pixel_clk - clk_set_rate failed\n", __func__);
clk_enable(ctrl_pdata->esc_clk);
clk_enable(ctrl_pdata->byte_clk);
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index b96e093..e5f8a69 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -41,6 +41,9 @@
#include <linux/android_pmem.h>
#include <linux/leds.h>
#include <linux/pm_runtime.h>
+#include <linux/sync.h>
+#include <linux/sw_sync.h>
+#include <linux/file.h>
#define MSM_FB_C
#include "msm_fb.h"
@@ -121,6 +124,9 @@
#define MSM_FB_MAX_DBGFS 1024
#define MAX_BACKLIGHT_BRIGHTNESS 255
+/* 200 ms for time out */
+#define WAIT_FENCE_TIMEOUT 200
+
int msm_fb_debugfs_file_index;
struct dentry *msm_fb_debugfs_root;
struct dentry *msm_fb_debugfs_file[MSM_FB_MAX_DBGFS];
@@ -419,6 +425,16 @@
pdev_list[pdev_list_cnt++] = pdev;
msm_fb_create_sysfs(pdev);
+ if (mfd->timeline == NULL) {
+ mfd->timeline = sw_sync_timeline_create("mdp-timeline");
+ if (mfd->timeline == NULL) {
+ pr_err("%s: cannot create time line", __func__);
+ return -ENOMEM;
+ } else {
+ mfd->timeline_value = 0;
+ }
+ }
+
return 0;
}
@@ -1677,6 +1693,7 @@
struct mdp_dirty_region dirty;
struct mdp_dirty_region *dirtyPtr = NULL;
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ int i, ret;
/*
* If framebuffer is 2, io pen display is not allowed.
@@ -1748,11 +1765,25 @@
mutex_unlock(&msm_fb_notify_update_sem);
down(&msm_fb_pan_sem);
-
+ /* buf sync */
+ for (i = 0; i < mfd->acq_fen_cnt; i++) {
+ ret = sync_fence_wait(mfd->acq_fen[i], WAIT_FENCE_TIMEOUT);
+ sync_fence_put(mfd->acq_fen[i]);
+ if (ret < 0) {
+ pr_err("%s: sync_fence_wait failed! ret = %x\n",
+ __func__, ret);
+ break;
+ }
+ }
+ mfd->acq_fen_cnt = 0;
if (info->node == 0 && !(mfd->cont_splash_done)) { /* primary */
mdp_set_dma_pan_info(info, NULL, TRUE);
if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) {
pr_err("%s: can't turn on display!\n", __func__);
+ if (mfd->timeline) {
+ sw_sync_timeline_inc(mfd->timeline, 2);
+ mfd->timeline_value += 2;
+ }
return -EINVAL;
}
}
@@ -1760,6 +1791,12 @@
mdp_set_dma_pan_info(info, dirtyPtr,
(var->activate & FB_ACTIVATE_VBL));
mdp_dma_pan_update(info);
+ if (mfd->timeline) {
+ sw_sync_timeline_inc(mfd->timeline, 1);
+ mfd->timeline_value++;
+ }
+ mfd->last_rel_fence = mfd->cur_rel_fence;
+ mfd->cur_rel_fence = 0;
up(&msm_fb_pan_sem);
if (unset_bl_level && !bl_updated)
@@ -3331,6 +3368,76 @@
return ret;
}
+static int msmfb_handle_buf_sync_ioctl(struct msm_fb_data_type *mfd,
+ struct mdp_buf_sync *buf_sync)
+{
+ int i, fence_cnt = 0, ret;
+ int acq_fen_fd[MDP_MAX_FENCE_FD];
+ struct sync_fence *fence;
+
+ if ((buf_sync->acq_fen_fd_cnt == 0) ||
+ (buf_sync->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) ||
+ (mfd->timeline == NULL))
+ return -EINVAL;
+
+ ret = copy_from_user(acq_fen_fd, buf_sync->acq_fen_fd,
+ buf_sync->acq_fen_fd_cnt * sizeof(int));
+ if (ret) {
+ pr_err("%s:copy_from_user failed", __func__);
+ return ret;
+ }
+ for (i = 0; i < buf_sync->acq_fen_fd_cnt; i++) {
+ fence = sync_fence_fdget(acq_fen_fd[i]);
+ if (fence == NULL) {
+ pr_info("%s: null fence! i=%d fd=%d\n", __func__, i,
+ acq_fen_fd[i]);
+ ret = -EINVAL;
+ break;
+ }
+ mfd->acq_fen[i] = fence;
+ }
+ fence_cnt = i;
+ if (ret)
+ goto buf_sync_err_1;
+ mfd->cur_rel_sync_pt = sw_sync_pt_create(mfd->timeline,
+ mfd->timeline_value + 2);
+ if (mfd->cur_rel_sync_pt == NULL) {
+ pr_err("%s: cannot create sync point", __func__);
+ ret = -ENOMEM;
+ goto buf_sync_err_1;
+ }
+ /* create fence */
+ mfd->cur_rel_fence = sync_fence_create("mdp-fence",
+ mfd->cur_rel_sync_pt);
+ if (mfd->cur_rel_fence == NULL) {
+ sync_pt_free(mfd->cur_rel_sync_pt);
+ mfd->cur_rel_sync_pt = NULL;
+ pr_err("%s: cannot create fence", __func__);
+ ret = -ENOMEM;
+ goto buf_sync_err_1;
+ }
+ /* create fd */
+ mfd->cur_rel_fen_fd = get_unused_fd_flags(0);
+ sync_fence_install(mfd->cur_rel_fence, mfd->cur_rel_fen_fd);
+ ret = copy_to_user(buf_sync->rel_fen_fd,
+ &mfd->cur_rel_fen_fd, sizeof(int));
+ if (ret) {
+ pr_err("%s:copy_to_user failed", __func__);
+ goto buf_sync_err_2;
+ }
+ mfd->acq_fen_cnt = buf_sync->acq_fen_fd_cnt;
+ return ret;
+buf_sync_err_2:
+ sync_fence_put(mfd->cur_rel_fence);
+ put_unused_fd(mfd->cur_rel_fen_fd);
+ mfd->cur_rel_fence = NULL;
+ mfd->cur_rel_fen_fd = 0;
+buf_sync_err_1:
+ for (i = 0; i < fence_cnt; i++)
+ sync_fence_put(mfd->acq_fen[i]);
+ mfd->acq_fen_cnt = 0;
+ return ret;
+}
static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg)
{
@@ -3349,6 +3456,7 @@
struct mdp_page_protection fb_page_protection;
struct msmfb_mdp_pp mdp_pp;
struct msmfb_metadata mdp_metadata;
+ struct mdp_buf_sync buf_sync;
int ret = 0;
switch (cmd) {
@@ -3636,6 +3744,16 @@
if (ret == 1)
ret = copy_to_user(argp, &mdp_pp, sizeof(mdp_pp));
break;
+ case MSMFB_BUFFER_SYNC:
+ ret = copy_from_user(&buf_sync, argp, sizeof(buf_sync));
+ if (ret)
+ return ret;
+
+ ret = msmfb_handle_buf_sync_ioctl(mfd, &buf_sync);
+
+ if (!ret)
+ ret = copy_to_user(argp, &buf_sync, sizeof(buf_sync));
+ break;
case MSMFB_METADATA_SET:
ret = copy_from_user(&mdp_metadata, argp, sizeof(mdp_metadata));
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index 34cb1fc..7e1716a 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -197,6 +197,14 @@
void *cpu_pm_hdl;
u32 avtimer_phy;
int vsync_sysfs_created;
+ u32 acq_fen_cnt;
+ struct sync_fence *acq_fen[MDP_MAX_FENCE_FD];
+ int cur_rel_fen_fd;
+ struct sync_pt *cur_rel_sync_pt;
+ struct sync_fence *cur_rel_fence;
+ struct sync_fence *last_rel_fence;
+ struct sw_sync_timeline *timeline;
+ int timeline_value;
};
struct dentry *msm_fb_get_debugfs_root(void);
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index afc5130..1c69d8f 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -25,7 +25,7 @@
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
-#include <linux/android_pmem.h>
+
#include <linux/clk.h>
#include <linux/timer.h>
#include <mach/msm_subsystem_map.h>
@@ -48,8 +48,6 @@
static dev_t vid_dec_dev_num;
static struct class *vid_dec_class;
-static unsigned int vidc_mmu_subsystem[] = {
- MSM_SUBSYSTEM_VIDEO};
static s32 vid_dec_get_empty_client_index(void)
{
u32 i, found = false;
@@ -875,11 +873,8 @@
{
struct vcd_property_hdr vcd_property_hdr;
struct vcd_property_meta_buffer *vcd_meta_buffer = NULL;
- struct msm_mapped_buffer *mapped_buffer = NULL;
- struct msm_mapped_buffer *mapped_buffer_iommu = NULL;
u32 vcd_status = VCD_ERR_FAIL;
- u32 len = 0, flags = 0, len_iommu = 0, flags_iommu = 0, buf_size = 0;
- struct file *file, *file_iommu;
+ u32 len = 0, len_iommu = 0, buf_size = 0;
int rc = 0;
unsigned long ionflag = 0, ionflag_iommu = 0;
unsigned long buffer_size = 0, buffer_size_iommu = 0;
@@ -903,54 +898,8 @@
vcd_meta_buffer->pmem_fd_iommu = meta_buffers->pmem_fd_iommu;
if (!vcd_get_ion_status()) {
- if (get_pmem_file(vcd_meta_buffer->pmem_fd,
- (unsigned long *) (&(vcd_meta_buffer->
- physical_addr)),
- (unsigned long *) (&vcd_meta_buffer->
- kernel_virtual_addr),
- (unsigned long *) (&len), &file)) {
- ERR("%s(): get_pmem_file failed\n", __func__);
- return false;
- }
- put_pmem_file(file);
- flags = MSM_SUBSYSTEM_MAP_IOVA;
- mapped_buffer = msm_subsystem_map_buffer(
- (unsigned long)vcd_meta_buffer->physical_addr,
- len, flags, vidc_mmu_subsystem,
- sizeof(vidc_mmu_subsystem)/
- sizeof(unsigned int));
- if (IS_ERR(mapped_buffer)) {
- pr_err("buffer map failed");
- return false;
- }
- vcd_meta_buffer->client_data = (void *) mapped_buffer;
- vcd_meta_buffer->dev_addr =
- (u8 *)mapped_buffer->iova[0];
-
- if (get_pmem_file(vcd_meta_buffer->pmem_fd_iommu,
- (unsigned long *) (&(vcd_meta_buffer->
- physical_addr_iommu)),
- (unsigned long *) (&vcd_meta_buffer->
- kernel_virt_addr_iommu),
- (unsigned long *) (&len_iommu), &file_iommu)) {
- ERR("%s(): get_pmem_file failed\n", __func__);
- return false;
- }
- put_pmem_file(file_iommu);
- flags_iommu = MSM_SUBSYSTEM_MAP_IOVA;
- mapped_buffer_iommu = msm_subsystem_map_buffer(
- (unsigned long)vcd_meta_buffer->physical_addr_iommu,
- len_iommu, flags_iommu, vidc_mmu_subsystem,
- sizeof(vidc_mmu_subsystem)/
- sizeof(unsigned int));
- if (IS_ERR(mapped_buffer_iommu)) {
- pr_err("buffer map failed");
- return false;
- }
- vcd_meta_buffer->client_data_iommu =
- (void *) mapped_buffer_iommu;
- vcd_meta_buffer->dev_addr_iommu =
- (u8 *)mapped_buffer_iommu->iova[0];
+ pr_err("PMEM Not available\n");
+ return false;
} else {
client_ctx->meta_buffer_ion_handle = ion_import_dma_buf(
client_ctx->user_ion_client,
@@ -1132,10 +1081,8 @@
{
struct vcd_property_hdr vcd_property_hdr;
struct vcd_property_h264_mv_buffer *vcd_h264_mv_buffer = NULL;
- struct msm_mapped_buffer *mapped_buffer = NULL;
u32 vcd_status = VCD_ERR_FAIL;
- u32 len = 0, flags = 0;
- struct file *file;
+ u32 len = 0;
int rc = 0;
unsigned long ionflag = 0;
unsigned long buffer_size = 0;
@@ -1156,28 +1103,8 @@
vcd_h264_mv_buffer->offset = mv_data->offset;
if (!vcd_get_ion_status()) {
- if (get_pmem_file(vcd_h264_mv_buffer->pmem_fd,
- (unsigned long *) (&(vcd_h264_mv_buffer->
- physical_addr)),
- (unsigned long *) (&vcd_h264_mv_buffer->
- kernel_virtual_addr),
- (unsigned long *) (&len), &file)) {
- ERR("%s(): get_pmem_file failed\n", __func__);
- return false;
- }
- put_pmem_file(file);
- flags = MSM_SUBSYSTEM_MAP_IOVA;
- mapped_buffer = msm_subsystem_map_buffer(
- (unsigned long)vcd_h264_mv_buffer->physical_addr, len,
- flags, vidc_mmu_subsystem,
- sizeof(vidc_mmu_subsystem)/
- sizeof(unsigned int));
- if (IS_ERR(mapped_buffer)) {
- pr_err("buffer map failed");
- return false;
- }
- vcd_h264_mv_buffer->client_data = (void *) mapped_buffer;
- vcd_h264_mv_buffer->dev_addr = (u8 *)mapped_buffer->iova[0];
+ pr_err("PMEM not available\n");
+ return false;
} else {
client_ctx->h264_mv_ion_handle = ion_import_dma_buf(
client_ctx->user_ion_client,
@@ -1818,7 +1745,6 @@
u32 vcd_status;
unsigned long kernel_vaddr, phy_addr, len;
unsigned long ker_vaddr;
- struct file *pmem_file;
u32 result = true;
void __user *arg = (void __user *)u_arg;
int rc = 0;
@@ -2133,12 +2059,8 @@
}
if (!vcd_get_ion_status()) {
- if (get_pmem_file(seq_header.pmem_fd,
- &phy_addr, &kernel_vaddr, &len, &pmem_file)) {
- ERR("%s(): get_pmem_file failed\n", __func__);
- return false;
- }
- put_pmem_file(pmem_file);
+ pr_err("PMEM Not available\n");
+ return -EINVAL;
} else {
client_ctx->seq_hdr_ion_handle = ion_import_dma_buf(
client_ctx->user_ion_client,
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index aa17f84..823626a 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -25,7 +25,7 @@
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
-#include <linux/android_pmem.h>
+
#include <linux/clk.h>
#include <media/msm/vidc_type.h>
#include <media/msm/vcd_api.h>
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index 14d8bfc..3dae4be1 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, 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
@@ -25,7 +25,7 @@
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
-#include <linux/android_pmem.h>
+
#include <linux/clk.h>
#include <mach/msm_subsystem_map.h>
#include <media/msm/vidc_type.h>
@@ -41,9 +41,6 @@
#endif
#define ERR(x...) printk(KERN_ERR x)
-static unsigned int vidc_mmu_subsystem[] = {
- MSM_SUBSYSTEM_VIDEO};
-
u32 vid_enc_set_get_base_cfg(struct video_client_ctx *client_ctx,
struct venc_basecfg *base_config, u32 set_flag)
@@ -1801,11 +1798,9 @@
struct venc_recon_addr *venc_recon)
{
u32 vcd_status = VCD_ERR_FAIL;
- u32 len, i, flags = 0;
- struct file *file;
+ u32 len, i;
struct vcd_property_hdr vcd_property_hdr;
struct vcd_property_enc_recon_buffer *control = NULL;
- struct msm_mapped_buffer *mapped_buffer = NULL;
int rc = -1;
unsigned long ionflag = 0;
unsigned long iova = 0;
@@ -1837,25 +1832,8 @@
control->user_virtual_addr = venc_recon->pbuffer;
if (!vcd_get_ion_status()) {
- if (get_pmem_file(control->pmem_fd, (unsigned long *)
- (&(control->physical_addr)), (unsigned long *)
- (&control->kernel_virtual_addr),
- (unsigned long *) (&len), &file)) {
- ERR("%s(): get_pmem_file failed\n", __func__);
- return false;
- }
- put_pmem_file(file);
- flags = MSM_SUBSYSTEM_MAP_IOVA;
- mapped_buffer = msm_subsystem_map_buffer(
- (unsigned long)control->physical_addr, len,
- flags, vidc_mmu_subsystem,
- sizeof(vidc_mmu_subsystem)/sizeof(unsigned int));
- if (IS_ERR(mapped_buffer)) {
- pr_err("buffer map failed");
- return false;
- }
- control->client_data = (void *) mapped_buffer;
- control->dev_addr = (u8 *)mapped_buffer->iova[0];
+ pr_err("PMEM not available\n");
+ return false;
} else {
client_ctx->recon_buffer_ion_handle[i] = ion_import_dma_buf(
client_ctx->user_ion_client, control->pmem_fd);
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c
index 9007145..72a1d5f 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.c
+++ b/drivers/video/msm/vidc/common/init/vidc_init.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, 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,7 +24,7 @@
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
-#include <linux/android_pmem.h>
+
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/debugfs.h>
@@ -49,7 +49,6 @@
static struct vidc_dev *vidc_device_p;
static dev_t vidc_dev_num;
static struct class *vidc_class;
-static unsigned int vidc_mmu_subsystem[] = {MSM_SUBSYSTEM_VIDEO};
static const struct file_operations vidc_fops = {
.owner = THIS_MODULE,
@@ -565,9 +564,8 @@
unsigned long len, phys_addr;
struct file *file = NULL;
u32 *num_of_buffers = NULL;
- u32 i, flags;
+ u32 i;
struct buf_addr_table *buf_addr_table;
- struct msm_mapped_buffer *mapped_buffer = NULL;
struct ion_handle *buff_ion_handle = NULL;
unsigned long ionflag = 0;
unsigned long iova = 0;
@@ -609,26 +607,8 @@
goto bail_out_add;
} else {
if (!vcd_get_ion_status()) {
- if (get_pmem_file(pmem_fd, &phys_addr,
- kernel_vaddr, &len, &file)) {
- ERR("%s(): get_pmem_file failed\n", __func__);
- goto bail_out_add;
- }
- put_pmem_file(file);
- flags = (buffer == BUFFER_TYPE_INPUT)
- ? MSM_SUBSYSTEM_MAP_IOVA :
- MSM_SUBSYSTEM_MAP_IOVA|MSM_SUBSYSTEM_ALIGN_IOVA_8K;
- mapped_buffer = msm_subsystem_map_buffer(phys_addr,
- length, flags, vidc_mmu_subsystem,
- sizeof(vidc_mmu_subsystem)/sizeof(unsigned int));
- if (IS_ERR(mapped_buffer)) {
- pr_err("buffer map failed");
- goto bail_out_add;
- }
- buf_addr_table[*num_of_buffers].client_data = (void *)
- mapped_buffer;
- buf_addr_table[*num_of_buffers].dev_addr =
- mapped_buffer->iova[0];
+ pr_err("PMEM not available\n");
+ return false;
} else {
buff_ion_handle = ion_import_dma_buf(
client_ctx->user_ion_client, pmem_fd);
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index e52effd..1afb701 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -1413,14 +1413,6 @@
goto out;
}
- if (be32_to_cpu(sb->s_first) == 0 ||
- be32_to_cpu(sb->s_first) >= journal->j_maxlen) {
- printk(KERN_WARNING
- "JBD2: Invalid start block of journal: %u\n",
- be32_to_cpu(sb->s_first));
- goto out;
- }
-
return 0;
out:
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index e35df2d..74c00bc 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1721,18 +1721,6 @@
\
save = resp->p;
-static bool seqid_mutating_err(__be32 err)
-{
- /* rfc 3530 section 8.1.5: */
- return err != nfserr_stale_clientid &&
- err != nfserr_stale_stateid &&
- err != nfserr_bad_stateid &&
- err != nfserr_bad_seqid &&
- err != nfserr_bad_xdr &&
- err != nfserr_resource &&
- err != nfserr_nofilehandle;
-}
-
/*
* Routine for encoding the result of a "seqid-mutating" NFSv4 operation. This
* is where sequence id's are incremented, and the replay cache is filled.
diff --git a/include/linux/ion.h b/include/linux/ion.h
index f159fe2..fb1c5f6 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -74,7 +74,6 @@
be converted to phys_addr_t. For the time being many kernel interfaces
do not accept phys_addr_t's that would have to */
#define ion_phys_addr_t unsigned long
-#define ion_virt_addr_t unsigned long
/**
* struct ion_platform_heap - defines a heap in the given platform
diff --git a/include/linux/mhl_defs.h b/include/linux/mhl_defs.h
index f9d1ce4..aa63e03 100644
--- a/include/linux/mhl_defs.h
+++ b/include/linux/mhl_defs.h
@@ -57,7 +57,7 @@
/* bits 4..7 */
#define MHL_VER_MAJOR (0x01 << 4)
/* bits 0..3 */
-#define MHL_VER_MINOR 0x01
+#define MHL_VER_MINOR 0x02
#define MHL_VERSION (MHL_VER_MAJOR | MHL_VER_MINOR)
/*Device Category*/
diff --git a/include/linux/mhl_devcap.h b/include/linux/mhl_devcap.h
index 40a87fe..37a0dc5 100644
--- a/include/linux/mhl_devcap.h
+++ b/include/linux/mhl_devcap.h
@@ -16,26 +16,23 @@
#define SILICON_IMAGE_ADOPTER_ID 322
#define TRANSCODER_DEVICE_ID 0x8334
-#define MHL_DEV_LD_AUDIO (0x01 << 2)
-#define MHL_DEV_LD_VIDEO (0x01 << 1)
-#define MHL_DEV_LD_MEDIA (0x01 << 3)
#define MHL_DEV_LD_GUI (0x01 << 7)
-#define MHL_LOGICAL_DEVICE_MAP (MHL_DEV_LD_AUDIO |\
- MHL_DEV_LD_VIDEO | MHL_DEV_LD_MEDIA | MHL_DEV_LD_GUI)
+#define MHL_LOGICAL_DEVICE_MAP MHL_DEV_LD_GUI
#define DEVCAP_VAL_DEV_STATE 0
#define DEVCAP_VAL_MHL_VERSION MHL_VERSION
-#define DEVCAP_VAL_DEV_CAT (MHL_DEV_CAT_SOURCE |\
- MHL_DEV_CATEGORY_POW_BIT)
+#define DEVCAP_VAL_DEV_CAT MHL_DEV_CAT_SOURCE
+
#define DEVCAP_VAL_ADOPTER_ID_H (uint8_t)(SILICON_IMAGE_ADOPTER_ID >> 8)
#define DEVCAP_VAL_ADOPTER_ID_L (uint8_t)(SILICON_IMAGE_ADOPTER_ID & 0xFF)
-#define DEVCAP_VAL_VID_LINK_MODE MHL_DEV_VID_LINK_SUPPRGB444
+#define DEVCAP_VAL_VID_LINK_MODE (MHL_DEV_VID_LINK_SUPPRGB444 |\
+ MHL_DEV_VID_LINK_SUPP_ISLANDS)
#define DEVCAP_VAL_AUD_LINK_MODE MHL_DEV_AUD_LINK_2CH
#define DEVCAP_VAL_VIDEO_TYPE 0
#define DEVCAP_VAL_LOG_DEV_MAP MHL_LOGICAL_DEVICE_MAP
#define DEVCAP_VAL_BANDWIDTH 0
#define DEVCAP_VAL_FEATURE_FLAG (MHL_FEATURE_RCP_SUPPORT |\
- MHL_FEATURE_RAP_SUPPORT | MHL_FEATURE_SP_SUPPORT)
+ MHL_FEATURE_RAP_SUPPORT | MHL_FEATURE_SP_SUPPORT)
#define DEVCAP_VAL_DEVICE_ID_H (uint8_t)(TRANSCODER_DEVICE_ID >> 8)
#define DEVCAP_VAL_DEVICE_ID_L (uint8_t)(TRANSCODER_DEVICE_ID & 0xFF)
#define DEVCAP_VAL_SCRATCHPAD_SIZE MHL_SCRATCHPAD_SIZE
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index e4aab43..9a4e61d 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -385,6 +385,9 @@
struct mmc_wr_pack_stats wr_pack_stats; /* packed commands stats*/
struct mmc_bkops_info bkops_info;
+
+ struct device_attribute rpm_attrib;
+ unsigned int idle_timeout;
};
/*
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 5f1e2d9..995f8a2 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -198,14 +198,13 @@
extern void mmc_release_host(struct mmc_host *host);
extern int mmc_try_claim_host(struct mmc_host *host);
extern void mmc_set_ios(struct mmc_host *host);
-extern int mmc_detect_card_removed(struct mmc_host *host);
-extern int mmc_flush_cache(struct mmc_card *);
-
extern int mmc_flush_cache(struct mmc_card *);
extern int mmc_detect_card_removed(struct mmc_host *host);
extern void mmc_blk_init_bkops_statistics(struct mmc_card *card);
+extern void mmc_rpm_hold(struct mmc_host *host, struct device *dev);
+extern void mmc_rpm_release(struct mmc_host *host, struct device *dev);
/**
* mmc_claim_host - exclusively claim a host
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 2bfd9a2..05271ba 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -60,8 +60,6 @@
#define MMC_TIMING_UHS_DDR50 5
#define MMC_TIMING_MMC_HS200 6
- unsigned char ddr; /* dual data rate used */
-
#define MMC_SDR_MODE 0
#define MMC_1_2V_DDR_MODE 1
#define MMC_1_8V_DDR_MODE 2
@@ -283,6 +281,8 @@
#define MMC_CAP2_INIT_BKOPS (1 << 16) /* Need to set BKOPS_EN */
#define MMC_CAP2_CLK_SCALE (1 << 17) /* Allow dynamic clk scaling */
#define MMC_CAP2_STOP_REQUEST (1 << 18) /* Allow stop ongoing request */
+/* Use runtime PM framework provided by MMC core */
+#define MMC_CAP2_CORE_RUNTIME_PM (1 << 19)
mmc_pm_flag_t pm_caps; /* supported pm features */
int clk_requests; /* internal reference counter */
@@ -386,7 +386,6 @@
} perf;
bool perf_enable;
#endif
-
struct mmc_ios saved_ios;
struct {
unsigned long busy_time_us;
@@ -483,9 +482,6 @@
int mmc_card_sleep(struct mmc_host *host);
int mmc_card_can_sleep(struct mmc_host *host);
-int mmc_host_enable(struct mmc_host *host);
-int mmc_host_disable(struct mmc_host *host);
-int mmc_host_lazy_disable(struct mmc_host *host);
int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *);
/* Module parameter */
@@ -543,4 +539,10 @@
return host->ios.clock;
}
#endif
+
+static inline int mmc_use_core_runtime_pm(struct mmc_host *host)
+{
+ return host->caps2 & MMC_CAP2_CORE_RUNTIME_PM;
+}
+
#endif /* LINUX_MMC_HOST_H */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 7f316a9..de145d6 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -348,7 +348,6 @@
#define EXT_CSD_PART_CONFIG_ACC_MASK (0x7)
#define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1)
-#define EXT_CSD_PART_CONFIG_ACC_BOOT1 (0x2)
#define EXT_CSD_PART_CONFIG_ACC_RPMB (0x3)
#define EXT_CSD_PART_CONFIG_ACC_GP0 (0x4)
@@ -390,14 +389,6 @@
#define EXT_CSD_POWER_OFF_SHORT 2
#define EXT_CSD_POWER_OFF_LONG 3
-#define EXT_CSD_RST_N_EN_MASK 0x3
-#define EXT_CSD_RST_N_ENABLED 1 /* RST_n is enabled on card */
-
-#define EXT_CSD_NO_POWER_NOTIFICATION 0
-#define EXT_CSD_POWER_ON 1
-#define EXT_CSD_POWER_OFF_SHORT 2
-#define EXT_CSD_POWER_OFF_LONG 3
-
#define EXT_CSD_PWR_CL_8BIT_MASK 0xF0 /* 8 bit PWR CLS */
#define EXT_CSD_PWR_CL_4BIT_MASK 0x0F /* 8 bit PWR CLS */
#define EXT_CSD_PWR_CL_8BIT_SHIFT 4
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index bd24575..f26b903 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -18,6 +18,11 @@
#include <linux/mmc/host.h>
#include <linux/pm_qos.h>
+struct sdhci_next {
+ unsigned int sg_count;
+ s32 cookie;
+};
+
struct sdhci_host {
/* Data set by hardware interface driver */
const char *hw_name; /* Hardware bus name */
@@ -191,6 +196,8 @@
unsigned int cpu_dma_latency_us;
struct pm_qos_request pm_qos_req_dma;
+ struct sdhci_next next_data;
+
unsigned long private[0] ____cacheline_aligned;
};
#endif /* LINUX_MMC_SDHCI_H */
diff --git a/include/linux/msm_audio_acdb.h b/include/linux/msm_audio_acdb.h
index f0c4915..646c22e 100644
--- a/include/linux/msm_audio_acdb.h
+++ b/include/linux/msm_audio_acdb.h
@@ -53,6 +53,10 @@
(AUDIO_MAX_COMMON_IOCTL_NUM+23), unsigned)
#define AUDIO_SET_ASM_CUSTOM_TOPOLOGY _IOW(AUDIO_IOCTL_MAGIC, \
(AUDIO_MAX_COMMON_IOCTL_NUM+24), unsigned)
+#define AUDIO_SET_SPEAKER_PROT _IOW(AUDIO_IOCTL_MAGIC, 25, \
+ struct msm_spk_prot_cfg)
+#define AUDIO_GET_SPEAKER_PROT _IOR(AUDIO_IOCTL_MAGIC, 26, \
+ struct msm_spk_prot_status)
#define AUDIO_MAX_ACDB_IOCTL (AUDIO_MAX_COMMON_IOCTL_NUM+30)
@@ -67,6 +71,19 @@
uint16_t gain;
};
+struct msm_spk_prot_cfg {
+ int r0;
+ int t0;
+ uint32_t mode; /*0 - Start spk prot
+ 1 - Start calib
+ 2 - Disable spk prot*/
+};
+
+struct msm_spk_prot_status {
+ int r0;
+ int status;
+};
+
/* For Real-Time Audio Calibration */
#define AUDIO_GET_RTAC_ADM_INFO _IOR(AUDIO_IOCTL_MAGIC, \
(AUDIO_MAX_ACDB_IOCTL+1), unsigned)
diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h
index ff22e12..a683ed4 100644
--- a/include/linux/msm_ion.h
+++ b/include/linux/msm_ion.h
@@ -163,7 +163,7 @@
enum ion_fixed_position fixed_position;
int iommu_map_all;
int iommu_2x_map_domain;
- ion_virt_addr_t *virt_addr;
+ void *virt_addr;
int (*request_region)(void *);
int (*release_region)(void *);
void *(*setup_region)(void);
diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h
index 5285317..569781f 100644
--- a/include/linux/pm_wakeup.h
+++ b/include/linux/pm_wakeup.h
@@ -34,6 +34,7 @@
* @total_time: Total time this wakeup source has been active.
* @max_time: Maximum time this wakeup source has been continuously active.
* @last_time: Monotonic clock when the wakeup source's was touched last time.
+ * @prevent_sleep_time: Total time this source has been preventing autosleep.
* @event_count: Number of signaled wakeup events.
* @active_count: Number of times the wakeup sorce was activated.
* @relax_count: Number of times the wakeup sorce was deactivated.
@@ -51,12 +52,15 @@
ktime_t total_time;
ktime_t max_time;
ktime_t last_time;
+ ktime_t start_prevent_time;
+ ktime_t prevent_sleep_time;
unsigned long event_count;
unsigned long active_count;
unsigned long relax_count;
unsigned long expire_count;
unsigned long wakeup_count;
bool active:1;
+ bool autosleep_enabled:1;
};
#ifdef CONFIG_PM_SLEEP
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index ac1c114..cd83059 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -356,8 +356,9 @@
extern bool events_check_enabled;
extern bool pm_wakeup_pending(void);
-extern bool pm_get_wakeup_count(unsigned int *count);
+extern bool pm_get_wakeup_count(unsigned int *count, bool block);
extern bool pm_save_wakeup_count(unsigned int count);
+extern void pm_wakep_autosleep_enabled(bool set);
static inline void lock_system_sleep(void)
{
@@ -407,6 +408,17 @@
#endif /* !CONFIG_PM_SLEEP */
+#ifdef CONFIG_PM_AUTOSLEEP
+
+/* kernel/power/autosleep.c */
+void queue_up_suspend_work(void);
+
+#else /* !CONFIG_PM_AUTOSLEEP */
+
+static inline void queue_up_suspend_work(void) {}
+
+#endif /* !CONFIG_PM_AUTOSLEEP */
+
#ifdef CONFIG_ARCH_SAVE_PAGE_KEYS
/*
* The ARCH_SAVE_PAGE_KEYS functions can be used by an architecture
diff --git a/include/linux/usb/android_composite.h b/include/linux/usb/android_composite.h
deleted file mode 100644
index 438dfa4..0000000
--- a/include/linux/usb/android_composite.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Platform data for Android USB
- *
- * Copyright (C) 2008 Google, Inc.
- * Author: Mike Lockwood <lockwood@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-#ifndef __LINUX_USB_ANDROID_H
-#define __LINUX_USB_ANDROID_H
-
-#include <linux/usb/composite.h>
-#include <linux/if_ether.h>
-
-struct android_usb_function {
- struct list_head list;
- char *name;
- int (*bind_config)(struct usb_configuration *c);
-};
-
-struct android_usb_product {
- /* Default product ID. */
- __u16 product_id;
-
- /* List of function names associated with this product.
- * This is used to compute the USB product ID dynamically
- * based on which functions are enabled.
- */
- int num_functions;
- char **functions;
-};
-
-struct android_usb_platform_data {
- /* USB device descriptor fields */
- __u16 vendor_id;
-
- /* Default product ID. */
- __u16 product_id;
-
- __u16 version;
-
- char *product_name;
- char *manufacturer_name;
- char *serial_number;
-
- /* List of available USB products.
- * This is used to compute the USB product ID dynamically
- * based on which functions are enabled.
- * if num_products is zero or no match can be found,
- * we use the default product ID
- */
- int num_products;
- struct android_usb_product *products;
-
- /* List of all supported USB functions.
- * This list is used to define the order in which
- * the functions appear in the configuration's list of USB interfaces.
- * This is necessary to avoid depending upon the order in which
- * the individual function drivers are initialized.
- */
- int num_functions;
- char **functions;
-};
-
-/* Platform data for "usb_mass_storage" driver. */
-struct usb_mass_storage_platform_data {
- /* Contains values for the SC_INQUIRY SCSI command. */
- char *vendor;
- char *product;
- int release;
-
- char can_stall;
- /* number of LUNS */
- int nluns;
-};
-
-/* Platform data for USB ethernet driver. */
-struct usb_ether_platform_data {
- u8 ethaddr[ETH_ALEN];
- u32 vendorID;
- const char *vendorDescr;
-};
-
-extern void android_register_function(struct android_usb_function *f);
-
-extern int android_enable_function(struct usb_function *f, int enable);
-
-
-#endif /* __LINUX_USB_ANDROID_H */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index c7c6b05..c5943c9 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -412,6 +412,7 @@
/*standalone latency is required when HSCI is active*/
u32 standalone_latency;
bool pool_64_bit_align;
+ bool enable_hbm;
};
struct msm_usb_host_platform_data {
diff --git a/include/linux/wakelock.h b/include/linux/wakelock.h
index 5b2d0f3..f4a698a 100644
--- a/include/linux/wakelock.h
+++ b/include/linux/wakelock.h
@@ -1,6 +1,6 @@
/* include/linux/wakelock.h
*
- * Copyright (C) 2007-2008 Google, Inc.
+ * Copyright (C) 2007-2012 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -16,14 +16,12 @@
#ifndef _LINUX_WAKELOCK_H
#define _LINUX_WAKELOCK_H
-#include <linux/list.h>
#include <linux/ktime.h>
+#include <linux/device.h>
/* A wake_lock prevents the system from entering suspend or other low power
* states when active. If the type is set to WAKE_LOCK_SUSPEND, the wake_lock
- * prevents a full system suspend. If the type is WAKE_LOCK_IDLE, low power
- * states that cause large interrupt latencies or that disable a set of
- * interrupts will not entered from idle until the wake_locks are released.
+ * prevents a full system suspend.
*/
enum {
@@ -32,59 +30,38 @@
};
struct wake_lock {
-#ifdef CONFIG_HAS_WAKELOCK
- struct list_head link;
- int flags;
- const char *name;
- unsigned long expires;
-#ifdef CONFIG_WAKELOCK_STAT
- struct {
- int count;
- int expire_count;
- int wakeup_count;
- ktime_t total_time;
- ktime_t prevent_suspend_time;
- ktime_t max_time;
- ktime_t last_time;
- } stat;
-#endif
-#endif
+ struct wakeup_source ws;
};
-#ifdef CONFIG_HAS_WAKELOCK
-
-void wake_lock_init(struct wake_lock *lock, int type, const char *name);
-void wake_lock_destroy(struct wake_lock *lock);
-void wake_lock(struct wake_lock *lock);
-void wake_lock_timeout(struct wake_lock *lock, long timeout);
-void wake_unlock(struct wake_lock *lock);
-
-/* wake_lock_active returns a non-zero value if the wake_lock is currently
- * locked. If the wake_lock has a timeout, it does not check the timeout
- * but if the timeout had aready been checked it will return 0.
- */
-int wake_lock_active(struct wake_lock *lock);
-
-/* has_wake_lock returns 0 if no wake locks of the specified type are active,
- * and non-zero if one or more wake locks are held. Specifically it returns
- * -1 if one or more wake locks with no timeout are active or the
- * number of jiffies until all active wake locks time out.
- */
-long has_wake_lock(int type);
-
-#else
-
static inline void wake_lock_init(struct wake_lock *lock, int type,
- const char *name) {}
-static inline void wake_lock_destroy(struct wake_lock *lock) {}
-static inline void wake_lock(struct wake_lock *lock) {}
-static inline void wake_lock_timeout(struct wake_lock *lock, long timeout) {}
-static inline void wake_unlock(struct wake_lock *lock) {}
+ const char *name)
+{
+ wakeup_source_init(&lock->ws, name);
+}
-static inline int wake_lock_active(struct wake_lock *lock) { return 0; }
-static inline long has_wake_lock(int type) { return 0; }
+static inline void wake_lock_destroy(struct wake_lock *lock)
+{
+ wakeup_source_trash(&lock->ws);
+}
+
+static inline void wake_lock(struct wake_lock *lock)
+{
+ __pm_stay_awake(&lock->ws);
+}
+
+static inline void wake_lock_timeout(struct wake_lock *lock, long timeout)
+{
+ __pm_wakeup_event(&lock->ws, jiffies_to_msecs(timeout));
+}
+
+static inline void wake_unlock(struct wake_lock *lock)
+{
+ __pm_relax(&lock->ws);
+}
+
+static inline int wake_lock_active(struct wake_lock *lock)
+{
+ return lock->ws.active;
+}
#endif
-
-#endif
-
diff --git a/include/media/gpio-ir-recv.h b/include/media/gpio-ir-recv.h
index 63f40f7..a81f0bb 100644
--- a/include/media/gpio-ir-recv.h
+++ b/include/media/gpio-ir-recv.h
@@ -14,7 +14,7 @@
#define __GPIO_IR_RECV_H__
struct gpio_ir_recv_platform_data {
- unsigned int gpio_nr;
+ int gpio_nr;
bool active_low;
bool can_wakeup;
u32 swfi_latency;
diff --git a/include/media/msm/vidc_type.h b/include/media/msm/vidc_type.h
index 77bae5a..5463fc6 100644
--- a/include/media/msm/vidc_type.h
+++ b/include/media/msm/vidc_type.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, 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
@@ -21,7 +21,7 @@
#include <linux/list.h>
#include <linux/time.h>
#include <linux/dma-mapping.h>
-#include <linux/android_pmem.h>
+
#define DDL_MSG_LOG 0
#define DEBUG 0
diff --git a/include/media/radio-iris.h b/include/media/radio-iris.h
index e3c4567..84789f1 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -52,6 +52,27 @@
#define FM_TX_PHY_CFG_MODE 0x3c
#define FM_TX_PHY_CFG_LEN 0x10
#define FM_TX_PWR_GAIN_OFFSET 14
+/**RDS CONFIG MODE**/
+#define FM_RDS_CNFG_MODE 0x0f
+#define FM_RDS_CNFG_LEN 0x10
+#define AF_RMSSI_TH_LSB_OFFSET 10
+#define AF_RMSSI_TH_MSB_OFFSET 11
+#define AF_RMSSI_SAMPLES_OFFSET 15
+/**RX CONFIG MODE**/
+#define FM_RX_CONFG_MODE 0x15
+#define FM_RX_CNFG_LEN 0x20
+#define GD_CH_RMSSI_TH_OFFSET 12
+#define MAX_GD_CH_RMSSI_TH 127
+#define SRCH_ALGO_TYPE_OFFSET 25
+#define SINRFIRSTSTAGE_OFFSET 26
+#define RMSSIFIRSTSTAGE_OFFSET 27
+#define CF0TH12_BYTE1_OFFSET 8
+#define CF0TH12_BYTE2_OFFSET 9
+#define CF0TH12_BYTE3_OFFSET 10
+#define CF0TH12_BYTE4_OFFSET 11
+#define MAX_SINR_FIRSTSTAGE 127
+#define MAX_RMSSI_FIRSTSTAGE 127
+
/* HCI timeouts */
#define RADIO_HCI_TIMEOUT (10000) /* 10 seconds */
@@ -658,6 +679,14 @@
V4L2_CID_PRIVATE_SPUR_SELECTION,
V4L2_CID_PRIVATE_UPDATE_SPUR_TABLE,
V4L2_CID_PRIVATE_VALID_CHANNEL,
+ V4L2_CID_PRIVATE_AF_RMSSI_TH,
+ V4L2_CID_PRIVATE_AF_RMSSI_SAMPLES,
+ V4L2_CID_PRIVATE_GOOD_CH_RMSSI_TH,
+ V4L2_CID_PRIVATE_SRCHALGOTYPE,
+ V4L2_CID_PRIVATE_CF0TH12,
+ V4L2_CID_PRIVATE_SINRFIRSTSTAGE,
+ V4L2_CID_PRIVATE_RMSSIFIRSTSTAGE,
+
/*using private CIDs under userclass*/
V4L2_CID_PRIVATE_IRIS_READ_DEFAULT = 0x00980928,
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index efc11bb..c68d427 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -26,7 +26,6 @@
#define __HCI_CORE_H
#include <net/bluetooth/hci.h>
-#include <linux/wakelock.h>
/* HCI upper protocols */
#define HCI_PROTO_L2CAP 0
#define HCI_PROTO_SCO 1
@@ -327,7 +326,6 @@
struct work_struct work_add;
struct work_struct work_del;
- struct wake_lock idle_lock;
struct device dev;
atomic_t devref;
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 93f0aa90..bc68c24 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -6252,6 +6252,93 @@
/* Size in bytes of the variable payload in shared memory */
} __packed;
+/* This module represents the Rx processing of Feedback speaker protection.
+ * It contains the excursion control, thermal protection,
+ * analog clip manager features in it.
+ * This module id will support following param ids.
+ * - AFE_PARAM_ID_FBSP_MODE_RX_CFG
+ */
+
+#define AFE_MODULE_FB_SPKR_PROT_RX 0x0001021C
+
+#define AFE_PARAM_ID_FBSP_MODE_RX_CFG 0x0001021D
+
+struct asm_fbsp_mode_rx_cfg {
+ uint32_t minor_version;
+ uint32_t mode;
+} __packed;
+
+/* This module represents the VI processing of feedback speaker protection.
+ * It will receive Vsens and Isens from codec and generates necessary
+ * parameters needed by Rx processing.
+ * This module id will support following param ids.
+ * - AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG
+ * - AFE_PARAM_ID_CALIB_RES_CFG
+ * - AFE_PARAM_ID_FEEDBACK_PATH_CFG
+ */
+
+#define AFE_MODULE_FB_SPKR_PROT_VI_PROC 0x00010226
+
+#define AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG 0x0001022A
+
+struct asm_spkr_calib_vi_proc_cfg {
+ uint32_t minor_version;
+ int32_t r0_cali_q24;
+ int16_t t0_cali_q6;
+ int16_t reserved;
+} __packed;
+
+#define AFE_PARAM_ID_CALIB_RES_CFG 0x0001022B
+
+struct asm_calib_res_cfg {
+ uint32_t minor_version;
+ int32_t r0_cali_q24;
+ uint32_t th_vi_ca_state;
+} __packed;
+
+#define AFE_PARAM_ID_FEEDBACK_PATH_CFG 0x0001022C
+
+struct asm_feedback_path_cfg {
+ uint32_t minor_version;
+ int32_t dst_portid;
+ int32_t num_channels;
+ int32_t chan_info[4];
+} __packed;
+
+#define AFE_PARAM_ID_MODE_VI_PROC_CFG 0x00010227
+
+struct asm_mode_vi_proc_cfg {
+ uint32_t minor_version;
+ uint32_t cal_mode;
+} __packed;
+
+union afe_spkr_prot_config {
+ struct asm_fbsp_mode_rx_cfg mode_rx_cfg;
+ struct asm_spkr_calib_vi_proc_cfg vi_proc_cfg;
+ struct asm_feedback_path_cfg feedback_path_cfg;
+ struct asm_mode_vi_proc_cfg mode_vi_proc_cfg;
+} __packed;
+
+struct afe_spkr_prot_config_command {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+ union afe_spkr_prot_config prot_config;
+} __packed;
+
+struct afe_spkr_prot_get_vi_calib {
+ struct afe_port_cmd_get_param_v2 get_param;
+ struct afe_port_param_data_v2 pdata;
+ struct asm_calib_res_cfg res_cfg;
+} __packed;
+
+struct afe_spkr_prot_calib_get_resp {
+ uint32_t status;
+ struct afe_port_param_data_v2 pdata;
+ struct asm_calib_res_cfg res_cfg;
+} __packed;
+
+
/* SRS TRUMEDIA start */
/* topology */
#define SRS_TRUMEDIA_TOPOLOGY_ID 0x00010D90
@@ -6355,8 +6442,6 @@
} __packed;
/* SRS TruMedia end */
-
-
/* ERROR CODES */
/* Success. The operation completed with no errors. */
#define ADSP_EOK 0x00000000
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index 506e877..feac314 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -145,6 +145,9 @@
int afe_rt_proxy_port_read(u32 buf_addr_p, u32 mem_map_handle, int bytes);
int afe_port_start(u16 port_id, union afe_port_config *afe_config,
u32 rate);
+int afe_spk_prot_feed_back_cfg(int src_port, int dst_port,
+ int l_ch, int r_ch);
+int afe_spk_prot_get_calib_data(struct afe_spkr_prot_get_vi_calib *calib);
int afe_port_stop_nowait(int port_id);
int afe_apply_gain(u16 port_id, u16 gain);
int afe_q6_interface_prepare(void);
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 1878b6e..371ddf6 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -103,6 +103,33 @@
select HOTPLUG
select HOTPLUG_CPU
+config PM_AUTOSLEEP
+ bool "Opportunistic sleep"
+ depends on PM_SLEEP
+ default n
+ ---help---
+ Allow the kernel to trigger a system transition into a global sleep
+ state automatically whenever there are no active wakeup sources.
+
+config PM_WAKELOCKS
+ bool "User space wakeup sources interface"
+ depends on PM_SLEEP
+ default n
+ ---help---
+ Allow user space to create, activate and deactivate wakeup source
+ objects with the help of a sysfs-based interface.
+
+config PM_WAKELOCKS_LIMIT
+ int "Maximum number of user space wakeup sources (0 = no limit)"
+ range 0 100000
+ default 100
+ depends on PM_WAKELOCKS
+
+config PM_WAKELOCKS_GC
+ bool "Garbage collector for user space wakeup sources"
+ depends on PM_WAKELOCKS
+ default y
+
config PM_RUNTIME
bool "Run-time PM core functionality"
depends on !IA64_HP_SIM
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index 5ad8c75..29472bf 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -9,11 +9,7 @@
obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o
obj-$(CONFIG_HIBERNATION) += hibernate.o snapshot.o swap.o user.o \
block_io.o
-obj-$(CONFIG_WAKELOCK) += wakelock.o
-obj-$(CONFIG_USER_WAKELOCK) += userwakelock.o
-obj-$(CONFIG_EARLYSUSPEND) += earlysuspend.o
-obj-$(CONFIG_CONSOLE_EARLYSUSPEND) += consoleearlysuspend.o
-obj-$(CONFIG_FB_EARLYSUSPEND) += fbearlysuspend.o
-obj-$(CONFIG_SUSPEND_TIME) += suspend_time.o
+obj-$(CONFIG_PM_AUTOSLEEP) += autosleep.o
+obj-$(CONFIG_PM_WAKELOCKS) += wakelock.o
obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
diff --git a/kernel/power/autosleep.c b/kernel/power/autosleep.c
new file mode 100644
index 0000000..ca304046
--- /dev/null
+++ b/kernel/power/autosleep.c
@@ -0,0 +1,127 @@
+/*
+ * kernel/power/autosleep.c
+ *
+ * Opportunistic sleep support.
+ *
+ * Copyright (C) 2012 Rafael J. Wysocki <rjw@sisk.pl>
+ */
+
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/pm_wakeup.h>
+
+#include "power.h"
+
+static suspend_state_t autosleep_state;
+static struct workqueue_struct *autosleep_wq;
+/*
+ * Note: it is only safe to mutex_lock(&autosleep_lock) if a wakeup_source
+ * is active, otherwise a deadlock with try_to_suspend() is possible.
+ * Alternatively mutex_lock_interruptible() can be used. This will then fail
+ * if an auto_sleep cycle tries to freeze processes.
+ */
+static DEFINE_MUTEX(autosleep_lock);
+static struct wakeup_source *autosleep_ws;
+
+static void try_to_suspend(struct work_struct *work)
+{
+ unsigned int initial_count, final_count;
+
+ if (!pm_get_wakeup_count(&initial_count, true))
+ goto out;
+
+ mutex_lock(&autosleep_lock);
+
+ if (!pm_save_wakeup_count(initial_count)) {
+ mutex_unlock(&autosleep_lock);
+ goto out;
+ }
+
+ if (autosleep_state == PM_SUSPEND_ON) {
+ mutex_unlock(&autosleep_lock);
+ return;
+ }
+ if (autosleep_state >= PM_SUSPEND_MAX)
+ hibernate();
+ else
+ pm_suspend(autosleep_state);
+
+ mutex_unlock(&autosleep_lock);
+
+ if (!pm_get_wakeup_count(&final_count, false))
+ goto out;
+
+ /*
+ * If the wakeup occured for an unknown reason, wait to prevent the
+ * system from trying to suspend and waking up in a tight loop.
+ */
+ if (final_count == initial_count)
+ schedule_timeout_uninterruptible(HZ / 2);
+
+ out:
+ queue_up_suspend_work();
+}
+
+static DECLARE_WORK(suspend_work, try_to_suspend);
+
+void queue_up_suspend_work(void)
+{
+ if (!work_pending(&suspend_work) && autosleep_state > PM_SUSPEND_ON)
+ queue_work(autosleep_wq, &suspend_work);
+}
+
+suspend_state_t pm_autosleep_state(void)
+{
+ return autosleep_state;
+}
+
+int pm_autosleep_lock(void)
+{
+ return mutex_lock_interruptible(&autosleep_lock);
+}
+
+void pm_autosleep_unlock(void)
+{
+ mutex_unlock(&autosleep_lock);
+}
+
+int pm_autosleep_set_state(suspend_state_t state)
+{
+
+#ifndef CONFIG_HIBERNATION
+ if (state >= PM_SUSPEND_MAX)
+ return -EINVAL;
+#endif
+
+ __pm_stay_awake(autosleep_ws);
+
+ mutex_lock(&autosleep_lock);
+
+ autosleep_state = state;
+
+ __pm_relax(autosleep_ws);
+
+ if (state > PM_SUSPEND_ON) {
+ pm_wakep_autosleep_enabled(true);
+ queue_up_suspend_work();
+ } else {
+ pm_wakep_autosleep_enabled(false);
+ }
+
+ mutex_unlock(&autosleep_lock);
+ return 0;
+}
+
+int __init pm_autosleep_init(void)
+{
+ autosleep_ws = wakeup_source_register("autosleep");
+ if (!autosleep_ws)
+ return -ENOMEM;
+
+ autosleep_wq = alloc_ordered_workqueue("autosleep", 0);
+ if (autosleep_wq)
+ return 0;
+
+ wakeup_source_unregister(autosleep_ws);
+ return -ENOMEM;
+}
diff --git a/kernel/power/main.c b/kernel/power/main.c
index a1d13f5..b54da02 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -354,8 +354,7 @@
return (s - buf);
}
-static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
- const char *buf, size_t n)
+static suspend_state_t decode_state(const char *buf, size_t n)
{
#ifdef CONFIG_SUSPEND
#ifdef CONFIG_EARLYSUSPEND
@@ -367,34 +366,48 @@
#endif
char *p;
int len;
- int error = -EINVAL;
p = memchr(buf, '\n', n);
len = p ? p - buf : n;
- /* First, check if we are requested to hibernate */
- if (len == 4 && !strncmp(buf, "disk", len)) {
- error = hibernate();
- goto Exit;
- }
+ /* Check hibernation first. */
+ if (len == 4 && !strncmp(buf, "disk", len))
+ return PM_SUSPEND_MAX;
#ifdef CONFIG_SUSPEND
- for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
- if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) {
-#ifdef CONFIG_EARLYSUSPEND
- if (state == PM_SUSPEND_ON || valid_state(state)) {
- error = 0;
- request_suspend_state(state);
- break;
- }
-#else
- error = pm_suspend(state);
-#endif
- }
- }
+ for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++)
+ if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
+ return state;
#endif
- Exit:
+ return PM_SUSPEND_ON;
+}
+
+static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ suspend_state_t state;
+ int error;
+
+ error = pm_autosleep_lock();
+ if (error)
+ return error;
+
+ if (pm_autosleep_state() > PM_SUSPEND_ON) {
+ error = -EBUSY;
+ goto out;
+ }
+
+ state = decode_state(buf, n);
+ if (state < PM_SUSPEND_MAX)
+ error = pm_suspend(state);
+ else if (state == PM_SUSPEND_MAX)
+ error = hibernate();
+ else
+ error = -EINVAL;
+
+ out:
+ pm_autosleep_unlock();
return error ? error : n;
}
@@ -435,7 +448,8 @@
{
unsigned int val;
- return pm_get_wakeup_count(&val) ? sprintf(buf, "%u\n", val) : -EINTR;
+ return pm_get_wakeup_count(&val, true) ?
+ sprintf(buf, "%u\n", val) : -EINTR;
}
static ssize_t wakeup_count_store(struct kobject *kobj,
@@ -443,15 +457,106 @@
const char *buf, size_t n)
{
unsigned int val;
+ int error;
+ error = pm_autosleep_lock();
+ if (error)
+ return error;
+
+ if (pm_autosleep_state() > PM_SUSPEND_ON) {
+ error = -EBUSY;
+ goto out;
+ }
+
+ error = -EINVAL;
if (sscanf(buf, "%u", &val) == 1) {
if (pm_save_wakeup_count(val))
- return n;
+ error = n;
}
- return -EINVAL;
+
+ out:
+ pm_autosleep_unlock();
+ return error;
}
power_attr(wakeup_count);
+
+#ifdef CONFIG_PM_AUTOSLEEP
+static ssize_t autosleep_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ suspend_state_t state = pm_autosleep_state();
+
+ if (state == PM_SUSPEND_ON)
+ return sprintf(buf, "off\n");
+
+#ifdef CONFIG_SUSPEND
+ if (state < PM_SUSPEND_MAX)
+ return sprintf(buf, "%s\n", valid_state(state) ?
+ pm_states[state] : "error");
+#endif
+#ifdef CONFIG_HIBERNATION
+ return sprintf(buf, "disk\n");
+#else
+ return sprintf(buf, "error");
+#endif
+}
+
+static ssize_t autosleep_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ suspend_state_t state = decode_state(buf, n);
+ int error;
+
+ if (state == PM_SUSPEND_ON
+ && !(strncmp(buf, "off", 3) && strncmp(buf, "off\n", 4)))
+ return -EINVAL;
+
+ error = pm_autosleep_set_state(state);
+ return error ? error : n;
+}
+
+power_attr(autosleep);
+#endif /* CONFIG_PM_AUTOSLEEP */
+
+#ifdef CONFIG_PM_WAKELOCKS
+static ssize_t wake_lock_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ return pm_show_wakelocks(buf, true);
+}
+
+static ssize_t wake_lock_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ int error = pm_wake_lock(buf);
+ return error ? error : n;
+}
+
+power_attr(wake_lock);
+
+static ssize_t wake_unlock_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ return pm_show_wakelocks(buf, false);
+}
+
+static ssize_t wake_unlock_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ int error = pm_wake_unlock(buf);
+ return error ? error : n;
+}
+
+power_attr(wake_unlock);
+
+#endif /* CONFIG_PM_WAKELOCKS */
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM_TRACE
@@ -502,8 +607,6 @@
#endif
static struct attribute *g[] = {
- &touch_event_attr.attr,
- &touch_event_timer_attr.attr,
&state_attr.attr,
#ifdef CONFIG_PM_TRACE
&pm_trace_attr.attr,
@@ -512,6 +615,15 @@
#ifdef CONFIG_PM_SLEEP
&pm_async_attr.attr,
&wakeup_count_attr.attr,
+#ifdef CONFIG_PM_AUTOSLEEP
+ &autosleep_attr.attr,
+#endif
+#ifdef CONFIG_PM_WAKELOCKS
+ &wake_lock_attr.attr,
+ &wake_unlock_attr.attr,
+#endif
+ &touch_event_attr.attr,
+ &touch_event_timer_attr.attr,
#ifdef CONFIG_PM_DEBUG
&pm_test_attr.attr,
#endif
@@ -558,7 +670,10 @@
power_kobj = kobject_create_and_add("power", NULL);
if (!power_kobj)
return -ENOMEM;
- return sysfs_create_group(power_kobj, &attr_group);
+ error = sysfs_create_group(power_kobj, &attr_group);
+ if (error)
+ return error;
+ return pm_autosleep_init();
}
core_initcall(pm_init);
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 32e08a1..b0bd4be 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -265,31 +265,29 @@
}
#endif
-#ifdef CONFIG_WAKELOCK
+#ifdef CONFIG_PM_AUTOSLEEP
+
+/* kernel/power/autosleep.c */
+extern int pm_autosleep_init(void);
+extern int pm_autosleep_lock(void);
+extern void pm_autosleep_unlock(void);
+extern suspend_state_t pm_autosleep_state(void);
+extern int pm_autosleep_set_state(suspend_state_t state);
+
+#else /* !CONFIG_PM_AUTOSLEEP */
+
+static inline int pm_autosleep_init(void) { return 0; }
+static inline int pm_autosleep_lock(void) { return 0; }
+static inline void pm_autosleep_unlock(void) {}
+static inline suspend_state_t pm_autosleep_state(void) { return PM_SUSPEND_ON; }
+
+#endif /* !CONFIG_PM_AUTOSLEEP */
+
+#ifdef CONFIG_PM_WAKELOCKS
+
/* kernel/power/wakelock.c */
-extern struct workqueue_struct *suspend_work_queue;
-extern struct wake_lock main_wake_lock;
-extern suspend_state_t requested_suspend_state;
-extern void suspend_sys_sync_queue(void);
-extern int suspend_sys_sync_wait(void);
-#else
-static inline void suspend_sys_sync_queue(void) {}
-static inline int suspend_sys_sync_wait(void) { return 0; }
-#endif
+extern ssize_t pm_show_wakelocks(char *buf, bool show_active);
+extern int pm_wake_lock(const char *buf);
+extern int pm_wake_unlock(const char *buf);
-#ifdef CONFIG_USER_WAKELOCK
-ssize_t wake_lock_show(struct kobject *kobj, struct kobj_attribute *attr,
- char *buf);
-ssize_t wake_lock_store(struct kobject *kobj, struct kobj_attribute *attr,
- const char *buf, size_t n);
-ssize_t wake_unlock_show(struct kobject *kobj, struct kobj_attribute *attr,
- char *buf);
-ssize_t wake_unlock_store(struct kobject *kobj, struct kobj_attribute *attr,
- const char *buf, size_t n);
-#endif
-
-#ifdef CONFIG_EARLYSUSPEND
-/* kernel/power/earlysuspend.c */
-void request_suspend_state(suspend_state_t state);
-suspend_state_t get_suspend_state(void);
-#endif
+#endif /* !CONFIG_PM_WAKELOCKS */
diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c
index 2583856..c8fba33 100644
--- a/kernel/power/wakelock.c
+++ b/kernel/power/wakelock.c
@@ -1,712 +1,259 @@
-/* kernel/power/wakelock.c
+/*
+ * kernel/power/wakelock.c
*
- * Copyright (C) 2005-2008 Google, Inc.
+ * User space wakeup sources support.
*
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
+ * Copyright (C) 2012 Rafael J. Wysocki <rjw@sisk.pl>
*
- * 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 code is based on the analogous interface allowing user space to
+ * manipulate wakelocks on Android.
*/
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/rtc.h>
-#include <linux/suspend.h>
-#include <linux/syscalls.h> /* sys_sync */
-#include <linux/wakelock.h>
-#ifdef CONFIG_WAKELOCK_STAT
-#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/hrtimer.h>
+#include <linux/list.h>
+#include <linux/rbtree.h>
+#include <linux/slab.h>
+
+static DEFINE_MUTEX(wakelocks_lock);
+
+struct wakelock {
+ char *name;
+ struct rb_node node;
+ struct wakeup_source ws;
+#ifdef CONFIG_PM_WAKELOCKS_GC
+ struct list_head lru;
#endif
-#include "power.h"
-
-enum {
- DEBUG_EXIT_SUSPEND = 1U << 0,
- DEBUG_WAKEUP = 1U << 1,
- DEBUG_SUSPEND = 1U << 2,
- DEBUG_EXPIRE = 1U << 3,
- DEBUG_WAKE_LOCK = 1U << 4,
};
-static int debug_mask = DEBUG_EXIT_SUSPEND | DEBUG_WAKEUP;
-module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
-#define WAKE_LOCK_TYPE_MASK (0x0f)
-#define WAKE_LOCK_INITIALIZED (1U << 8)
-#define WAKE_LOCK_ACTIVE (1U << 9)
-#define WAKE_LOCK_AUTO_EXPIRE (1U << 10)
-#define WAKE_LOCK_PREVENTING_SUSPEND (1U << 11)
+static struct rb_root wakelocks_tree = RB_ROOT;
-static DEFINE_SPINLOCK(list_lock);
-static LIST_HEAD(inactive_locks);
-static struct list_head active_wake_locks[WAKE_LOCK_TYPE_COUNT];
-static int current_event_num;
-static int suspend_sys_sync_count;
-static DEFINE_SPINLOCK(suspend_sys_sync_lock);
-static struct workqueue_struct *suspend_sys_sync_work_queue;
-static DECLARE_COMPLETION(suspend_sys_sync_comp);
-struct workqueue_struct *suspend_work_queue;
-struct wake_lock main_wake_lock;
-suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;
-static struct wake_lock unknown_wakeup;
-static struct wake_lock suspend_backoff_lock;
-
-#define SUSPEND_BACKOFF_THRESHOLD 10
-#define SUSPEND_BACKOFF_INTERVAL 10000
-
-static unsigned suspend_short_count;
-
-#ifdef CONFIG_WAKELOCK_STAT
-static struct wake_lock deleted_wake_locks;
-static ktime_t last_sleep_time_update;
-static int wait_for_wakeup;
-
-int get_expired_time(struct wake_lock *lock, ktime_t *expire_time)
+ssize_t pm_show_wakelocks(char *buf, bool show_active)
{
- struct timespec ts;
- struct timespec kt;
- struct timespec tomono;
- struct timespec delta;
- struct timespec sleep;
- long timeout;
+ struct rb_node *node;
+ struct wakelock *wl;
+ char *str = buf;
+ char *end = buf + PAGE_SIZE;
- if (!(lock->flags & WAKE_LOCK_AUTO_EXPIRE))
- return 0;
- get_xtime_and_monotonic_and_sleep_offset(&kt, &tomono, &sleep);
- timeout = lock->expires - jiffies;
- if (timeout > 0)
- return 0;
- jiffies_to_timespec(-timeout, &delta);
- set_normalized_timespec(&ts, kt.tv_sec + tomono.tv_sec - delta.tv_sec,
- kt.tv_nsec + tomono.tv_nsec - delta.tv_nsec);
- *expire_time = timespec_to_ktime(ts);
- return 1;
-}
+ mutex_lock(&wakelocks_lock);
-
-static int print_lock_stat(struct seq_file *m, struct wake_lock *lock)
-{
- int lock_count = lock->stat.count;
- int expire_count = lock->stat.expire_count;
- ktime_t active_time = ktime_set(0, 0);
- ktime_t total_time = lock->stat.total_time;
- ktime_t max_time = lock->stat.max_time;
-
- ktime_t prevent_suspend_time = lock->stat.prevent_suspend_time;
- if (lock->flags & WAKE_LOCK_ACTIVE) {
- ktime_t now, add_time;
- int expired = get_expired_time(lock, &now);
- if (!expired)
- now = ktime_get();
- add_time = ktime_sub(now, lock->stat.last_time);
- lock_count++;
- if (!expired)
- active_time = add_time;
- else
- expire_count++;
- total_time = ktime_add(total_time, add_time);
- if (lock->flags & WAKE_LOCK_PREVENTING_SUSPEND)
- prevent_suspend_time = ktime_add(prevent_suspend_time,
- ktime_sub(now, last_sleep_time_update));
- if (add_time.tv64 > max_time.tv64)
- max_time = add_time;
+ for (node = rb_first(&wakelocks_tree); node; node = rb_next(node)) {
+ wl = rb_entry(node, struct wakelock, node);
+ if (wl->ws.active == show_active)
+ str += scnprintf(str, end - str, "%s ", wl->name);
}
+ if (str > buf)
+ str--;
- return seq_printf(m,
- "\"%s\"\t%d\t%d\t%d\t%lld\t%lld\t%lld\t%lld\t%lld\n",
- lock->name, lock_count, expire_count,
- lock->stat.wakeup_count, ktime_to_ns(active_time),
- ktime_to_ns(total_time),
- ktime_to_ns(prevent_suspend_time), ktime_to_ns(max_time),
- ktime_to_ns(lock->stat.last_time));
+ str += scnprintf(str, end - str, "\n");
+
+ mutex_unlock(&wakelocks_lock);
+ return (str - buf);
}
-static int wakelock_stats_show(struct seq_file *m, void *unused)
+#if CONFIG_PM_WAKELOCKS_LIMIT > 0
+static unsigned int number_of_wakelocks;
+
+static inline bool wakelocks_limit_exceeded(void)
{
- unsigned long irqflags;
- struct wake_lock *lock;
- int ret;
- int type;
-
- spin_lock_irqsave(&list_lock, irqflags);
-
- ret = seq_puts(m, "name\tcount\texpire_count\twake_count\tactive_since"
- "\ttotal_time\tsleep_time\tmax_time\tlast_change\n");
- list_for_each_entry(lock, &inactive_locks, link)
- ret = print_lock_stat(m, lock);
- for (type = 0; type < WAKE_LOCK_TYPE_COUNT; type++) {
- list_for_each_entry(lock, &active_wake_locks[type], link)
- ret = print_lock_stat(m, lock);
- }
- spin_unlock_irqrestore(&list_lock, irqflags);
- return 0;
+ return number_of_wakelocks > CONFIG_PM_WAKELOCKS_LIMIT;
}
-static void wake_unlock_stat_locked(struct wake_lock *lock, int expired)
+static inline void increment_wakelocks_number(void)
{
- ktime_t duration;
+ number_of_wakelocks++;
+}
+
+static inline void decrement_wakelocks_number(void)
+{
+ number_of_wakelocks--;
+}
+#else /* CONFIG_PM_WAKELOCKS_LIMIT = 0 */
+static inline bool wakelocks_limit_exceeded(void) { return false; }
+static inline void increment_wakelocks_number(void) {}
+static inline void decrement_wakelocks_number(void) {}
+#endif /* CONFIG_PM_WAKELOCKS_LIMIT */
+
+#ifdef CONFIG_PM_WAKELOCKS_GC
+#define WL_GC_COUNT_MAX 100
+#define WL_GC_TIME_SEC 300
+
+static LIST_HEAD(wakelocks_lru_list);
+static unsigned int wakelocks_gc_count;
+
+static inline void wakelocks_lru_add(struct wakelock *wl)
+{
+ list_add(&wl->lru, &wakelocks_lru_list);
+}
+
+static inline void wakelocks_lru_most_recent(struct wakelock *wl)
+{
+ list_move(&wl->lru, &wakelocks_lru_list);
+}
+
+static void wakelocks_gc(void)
+{
+ struct wakelock *wl, *aux;
ktime_t now;
- if (!(lock->flags & WAKE_LOCK_ACTIVE))
- return;
- if (get_expired_time(lock, &now))
- expired = 1;
- else
- now = ktime_get();
- lock->stat.count++;
- if (expired)
- lock->stat.expire_count++;
- duration = ktime_sub(now, lock->stat.last_time);
- lock->stat.total_time = ktime_add(lock->stat.total_time, duration);
- if (ktime_to_ns(duration) > ktime_to_ns(lock->stat.max_time))
- lock->stat.max_time = duration;
- lock->stat.last_time = ktime_get();
- if (lock->flags & WAKE_LOCK_PREVENTING_SUSPEND) {
- duration = ktime_sub(now, last_sleep_time_update);
- lock->stat.prevent_suspend_time = ktime_add(
- lock->stat.prevent_suspend_time, duration);
- lock->flags &= ~WAKE_LOCK_PREVENTING_SUSPEND;
- }
-}
-static void update_sleep_wait_stats_locked(int done)
-{
- struct wake_lock *lock;
- ktime_t now, etime, elapsed, add;
- int expired;
+ if (++wakelocks_gc_count <= WL_GC_COUNT_MAX)
+ return;
now = ktime_get();
- elapsed = ktime_sub(now, last_sleep_time_update);
- list_for_each_entry(lock, &active_wake_locks[WAKE_LOCK_SUSPEND], link) {
- expired = get_expired_time(lock, &etime);
- if (lock->flags & WAKE_LOCK_PREVENTING_SUSPEND) {
- if (expired)
- add = ktime_sub(etime, last_sleep_time_update);
+ list_for_each_entry_safe_reverse(wl, aux, &wakelocks_lru_list, lru) {
+ u64 idle_time_ns;
+ bool active;
+
+ spin_lock_irq(&wl->ws.lock);
+ idle_time_ns = ktime_to_ns(ktime_sub(now, wl->ws.last_time));
+ active = wl->ws.active;
+ spin_unlock_irq(&wl->ws.lock);
+
+ if (idle_time_ns < ((u64)WL_GC_TIME_SEC * NSEC_PER_SEC))
+ break;
+
+ if (!active) {
+ wakeup_source_remove(&wl->ws);
+ rb_erase(&wl->node, &wakelocks_tree);
+ list_del(&wl->lru);
+ kfree(wl->name);
+ kfree(wl);
+ decrement_wakelocks_number();
+ }
+ }
+ wakelocks_gc_count = 0;
+}
+#else /* !CONFIG_PM_WAKELOCKS_GC */
+static inline void wakelocks_lru_add(struct wakelock *wl) {}
+static inline void wakelocks_lru_most_recent(struct wakelock *wl) {}
+static inline void wakelocks_gc(void) {}
+#endif /* !CONFIG_PM_WAKELOCKS_GC */
+
+static struct wakelock *wakelock_lookup_add(const char *name, size_t len,
+ bool add_if_not_found)
+{
+ struct rb_node **node = &wakelocks_tree.rb_node;
+ struct rb_node *parent = *node;
+ struct wakelock *wl;
+
+ while (*node) {
+ int diff;
+
+ parent = *node;
+ wl = rb_entry(*node, struct wakelock, node);
+ diff = strncmp(name, wl->name, len);
+ if (diff == 0) {
+ if (wl->name[len])
+ diff = -1;
else
- add = elapsed;
- lock->stat.prevent_suspend_time = ktime_add(
- lock->stat.prevent_suspend_time, add);
+ return wl;
}
- if (done || expired)
- lock->flags &= ~WAKE_LOCK_PREVENTING_SUSPEND;
+ if (diff < 0)
+ node = &(*node)->rb_left;
else
- lock->flags |= WAKE_LOCK_PREVENTING_SUSPEND;
+ node = &(*node)->rb_right;
}
- last_sleep_time_update = now;
-}
-#endif
+ if (!add_if_not_found)
+ return ERR_PTR(-EINVAL);
+ if (wakelocks_limit_exceeded())
+ return ERR_PTR(-ENOSPC);
-static void expire_wake_lock(struct wake_lock *lock)
-{
-#ifdef CONFIG_WAKELOCK_STAT
- wake_unlock_stat_locked(lock, 1);
-#endif
- lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
- list_del(&lock->link);
- list_add(&lock->link, &inactive_locks);
- if (debug_mask & (DEBUG_WAKE_LOCK | DEBUG_EXPIRE))
- pr_info("expired wake lock %s\n", lock->name);
-}
+ /* Not found, we have to add a new one. */
+ wl = kzalloc(sizeof(*wl), GFP_KERNEL);
+ if (!wl)
+ return ERR_PTR(-ENOMEM);
-/* Caller must acquire the list_lock spinlock */
-static void print_active_locks(int type)
-{
- struct wake_lock *lock;
- bool print_expired = true;
-
- BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
- list_for_each_entry(lock, &active_wake_locks[type], link) {
- if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) {
- long timeout = lock->expires - jiffies;
- if (timeout > 0)
- pr_info("active wake lock %s, time left %ld\n",
- lock->name, timeout);
- else if (print_expired)
- pr_info("wake lock %s, expired\n", lock->name);
- } else {
- pr_info("active wake lock %s\n", lock->name);
- if (!(debug_mask & DEBUG_EXPIRE))
- print_expired = false;
- }
+ wl->name = kstrndup(name, len, GFP_KERNEL);
+ if (!wl->name) {
+ kfree(wl);
+ return ERR_PTR(-ENOMEM);
}
+ wl->ws.name = wl->name;
+ wakeup_source_add(&wl->ws);
+ rb_link_node(&wl->node, parent, node);
+ rb_insert_color(&wl->node, &wakelocks_tree);
+ wakelocks_lru_add(wl);
+ increment_wakelocks_number();
+ return wl;
}
-static long has_wake_lock_locked(int type)
+int pm_wake_lock(const char *buf)
{
- struct wake_lock *lock, *n;
- long max_timeout = 0;
+ const char *str = buf;
+ struct wakelock *wl;
+ u64 timeout_ns = 0;
+ size_t len;
+ int ret = 0;
- BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
- list_for_each_entry_safe(lock, n, &active_wake_locks[type], link) {
- if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) {
- long timeout = lock->expires - jiffies;
- if (timeout <= 0)
- expire_wake_lock(lock);
- else if (timeout > max_timeout)
- max_timeout = timeout;
- } else
- return -1;
+ while (*str && !isspace(*str))
+ str++;
+
+ len = str - buf;
+ if (!len)
+ return -EINVAL;
+
+ if (*str && *str != '\n') {
+ /* Find out if there's a valid timeout string appended. */
+ ret = kstrtou64(skip_spaces(str), 10, &timeout_ns);
+ if (ret)
+ return -EINVAL;
}
- return max_timeout;
-}
-long has_wake_lock(int type)
-{
- long ret;
- unsigned long irqflags;
- spin_lock_irqsave(&list_lock, irqflags);
- ret = has_wake_lock_locked(type);
- if (ret && (debug_mask & DEBUG_WAKEUP) && type == WAKE_LOCK_SUSPEND)
- print_active_locks(type);
- spin_unlock_irqrestore(&list_lock, irqflags);
+ mutex_lock(&wakelocks_lock);
+
+ wl = wakelock_lookup_add(buf, len, true);
+ if (IS_ERR(wl)) {
+ ret = PTR_ERR(wl);
+ goto out;
+ }
+ if (timeout_ns) {
+ u64 timeout_ms = timeout_ns + NSEC_PER_MSEC - 1;
+
+ do_div(timeout_ms, NSEC_PER_MSEC);
+ __pm_wakeup_event(&wl->ws, timeout_ms);
+ } else {
+ __pm_stay_awake(&wl->ws);
+ }
+
+ wakelocks_lru_most_recent(wl);
+
+ out:
+ mutex_unlock(&wakelocks_lock);
return ret;
}
-static void suspend_sys_sync(struct work_struct *work)
+int pm_wake_unlock(const char *buf)
{
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("PM: Syncing filesystems...\n");
+ struct wakelock *wl;
+ size_t len;
+ int ret = 0;
- sys_sync();
+ len = strlen(buf);
+ if (!len)
+ return -EINVAL;
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("sync done.\n");
+ if (buf[len-1] == '\n')
+ len--;
- spin_lock(&suspend_sys_sync_lock);
- suspend_sys_sync_count--;
- spin_unlock(&suspend_sys_sync_lock);
-}
-static DECLARE_WORK(suspend_sys_sync_work, suspend_sys_sync);
+ if (!len)
+ return -EINVAL;
-void suspend_sys_sync_queue(void)
-{
- int ret;
+ mutex_lock(&wakelocks_lock);
- spin_lock(&suspend_sys_sync_lock);
- ret = queue_work(suspend_sys_sync_work_queue, &suspend_sys_sync_work);
- if (ret)
- suspend_sys_sync_count++;
- spin_unlock(&suspend_sys_sync_lock);
-}
-
-static bool suspend_sys_sync_abort;
-static void suspend_sys_sync_handler(unsigned long);
-static DEFINE_TIMER(suspend_sys_sync_timer, suspend_sys_sync_handler, 0, 0);
-/* value should be less then half of input event wake lock timeout value
- * which is currently set to 5*HZ (see drivers/input/evdev.c)
- */
-#define SUSPEND_SYS_SYNC_TIMEOUT (HZ/4)
-static void suspend_sys_sync_handler(unsigned long arg)
-{
- if (suspend_sys_sync_count == 0) {
- complete(&suspend_sys_sync_comp);
- } else if (has_wake_lock(WAKE_LOCK_SUSPEND)) {
- suspend_sys_sync_abort = true;
- complete(&suspend_sys_sync_comp);
- } else {
- mod_timer(&suspend_sys_sync_timer, jiffies +
- SUSPEND_SYS_SYNC_TIMEOUT);
+ wl = wakelock_lookup_add(buf, len, false);
+ if (IS_ERR(wl)) {
+ ret = PTR_ERR(wl);
+ goto out;
}
-}
+ __pm_relax(&wl->ws);
-int suspend_sys_sync_wait(void)
-{
- suspend_sys_sync_abort = false;
+ wakelocks_lru_most_recent(wl);
+ wakelocks_gc();
- if (suspend_sys_sync_count != 0) {
- mod_timer(&suspend_sys_sync_timer, jiffies +
- SUSPEND_SYS_SYNC_TIMEOUT);
- wait_for_completion(&suspend_sys_sync_comp);
- }
- if (suspend_sys_sync_abort) {
- pr_info("suspend aborted....while waiting for sys_sync\n");
- return -EAGAIN;
- }
-
- return 0;
-}
-
-static void suspend_backoff(void)
-{
- pr_info("suspend: too many immediate wakeups, back off\n");
- wake_lock_timeout(&suspend_backoff_lock,
- msecs_to_jiffies(SUSPEND_BACKOFF_INTERVAL));
-}
-
-static void suspend(struct work_struct *work)
-{
- int ret;
- int entry_event_num;
- struct timespec ts_entry, ts_exit;
-
- if (has_wake_lock(WAKE_LOCK_SUSPEND)) {
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("suspend: abort suspend\n");
- return;
- }
-
- entry_event_num = current_event_num;
- suspend_sys_sync_queue();
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("suspend: enter suspend\n");
- getnstimeofday(&ts_entry);
- ret = pm_suspend(requested_suspend_state);
- getnstimeofday(&ts_exit);
-
- if (debug_mask & DEBUG_EXIT_SUSPEND) {
- struct rtc_time tm;
- rtc_time_to_tm(ts_exit.tv_sec, &tm);
- pr_info("suspend: exit suspend, ret = %d "
- "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,
- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec, ts_exit.tv_nsec);
- }
-
- if (ts_exit.tv_sec - ts_entry.tv_sec <= 1) {
- ++suspend_short_count;
-
- if (suspend_short_count == SUSPEND_BACKOFF_THRESHOLD) {
- suspend_backoff();
- suspend_short_count = 0;
- }
- } else {
- suspend_short_count = 0;
- }
-
- if (current_event_num == entry_event_num) {
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("suspend: pm_suspend returned with no event\n");
- wake_lock_timeout(&unknown_wakeup, HZ / 2);
- }
-}
-static DECLARE_WORK(suspend_work, suspend);
-
-static void expire_wake_locks(unsigned long data)
-{
- long has_lock;
- unsigned long irqflags;
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("expire_wake_locks: start\n");
- spin_lock_irqsave(&list_lock, irqflags);
- if (debug_mask & DEBUG_SUSPEND)
- print_active_locks(WAKE_LOCK_SUSPEND);
- has_lock = has_wake_lock_locked(WAKE_LOCK_SUSPEND);
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("expire_wake_locks: done, has_lock %ld\n", has_lock);
- if (has_lock == 0)
- queue_work(suspend_work_queue, &suspend_work);
- spin_unlock_irqrestore(&list_lock, irqflags);
-}
-static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);
-
-static int power_suspend_late(struct device *dev)
-{
- int ret = has_wake_lock(WAKE_LOCK_SUSPEND) ? -EAGAIN : 0;
-#ifdef CONFIG_WAKELOCK_STAT
- wait_for_wakeup = !ret;
-#endif
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("power_suspend_late return %d\n", ret);
+ out:
+ mutex_unlock(&wakelocks_lock);
return ret;
}
-
-static struct dev_pm_ops power_driver_pm_ops = {
- .suspend_noirq = power_suspend_late,
-};
-
-static struct platform_driver power_driver = {
- .driver.name = "power",
- .driver.pm = &power_driver_pm_ops,
-};
-static struct platform_device power_device = {
- .name = "power",
-};
-
-void wake_lock_init(struct wake_lock *lock, int type, const char *name)
-{
- unsigned long irqflags = 0;
-
- if (name)
- lock->name = name;
- BUG_ON(!lock->name);
-
- if (debug_mask & DEBUG_WAKE_LOCK)
- pr_info("wake_lock_init name=%s\n", lock->name);
-#ifdef CONFIG_WAKELOCK_STAT
- lock->stat.count = 0;
- lock->stat.expire_count = 0;
- lock->stat.wakeup_count = 0;
- lock->stat.total_time = ktime_set(0, 0);
- lock->stat.prevent_suspend_time = ktime_set(0, 0);
- lock->stat.max_time = ktime_set(0, 0);
- lock->stat.last_time = ktime_set(0, 0);
-#endif
- lock->flags = (type & WAKE_LOCK_TYPE_MASK) | WAKE_LOCK_INITIALIZED;
-
- INIT_LIST_HEAD(&lock->link);
- spin_lock_irqsave(&list_lock, irqflags);
- list_add(&lock->link, &inactive_locks);
- spin_unlock_irqrestore(&list_lock, irqflags);
-}
-EXPORT_SYMBOL(wake_lock_init);
-
-void wake_lock_destroy(struct wake_lock *lock)
-{
- unsigned long irqflags;
- if (debug_mask & DEBUG_WAKE_LOCK)
- pr_info("wake_lock_destroy name=%s\n", lock->name);
- spin_lock_irqsave(&list_lock, irqflags);
- lock->flags &= ~WAKE_LOCK_INITIALIZED;
-#ifdef CONFIG_WAKELOCK_STAT
- if (lock->stat.count) {
- deleted_wake_locks.stat.count += lock->stat.count;
- deleted_wake_locks.stat.expire_count += lock->stat.expire_count;
- deleted_wake_locks.stat.total_time =
- ktime_add(deleted_wake_locks.stat.total_time,
- lock->stat.total_time);
- deleted_wake_locks.stat.prevent_suspend_time =
- ktime_add(deleted_wake_locks.stat.prevent_suspend_time,
- lock->stat.prevent_suspend_time);
- deleted_wake_locks.stat.max_time =
- ktime_add(deleted_wake_locks.stat.max_time,
- lock->stat.max_time);
- }
-#endif
- list_del(&lock->link);
- spin_unlock_irqrestore(&list_lock, irqflags);
-}
-EXPORT_SYMBOL(wake_lock_destroy);
-
-static void wake_lock_internal(
- struct wake_lock *lock, long timeout, int has_timeout)
-{
- int type;
- unsigned long irqflags;
- long expire_in;
-
- spin_lock_irqsave(&list_lock, irqflags);
- type = lock->flags & WAKE_LOCK_TYPE_MASK;
- BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
- BUG_ON(!(lock->flags & WAKE_LOCK_INITIALIZED));
-#ifdef CONFIG_WAKELOCK_STAT
- if (type == WAKE_LOCK_SUSPEND && wait_for_wakeup) {
- if (debug_mask & DEBUG_WAKEUP)
- pr_info("wakeup wake lock: %s\n", lock->name);
- wait_for_wakeup = 0;
- lock->stat.wakeup_count++;
- }
- if ((lock->flags & WAKE_LOCK_AUTO_EXPIRE) &&
- (long)(lock->expires - jiffies) <= 0) {
- wake_unlock_stat_locked(lock, 0);
- lock->stat.last_time = ktime_get();
- }
-#endif
- if (!(lock->flags & WAKE_LOCK_ACTIVE)) {
- lock->flags |= WAKE_LOCK_ACTIVE;
-#ifdef CONFIG_WAKELOCK_STAT
- lock->stat.last_time = ktime_get();
-#endif
- }
- list_del(&lock->link);
- if (has_timeout) {
- if (debug_mask & DEBUG_WAKE_LOCK)
- pr_info("wake_lock: %s, type %d, timeout %ld.%03lu\n",
- lock->name, type, timeout / HZ,
- (timeout % HZ) * MSEC_PER_SEC / HZ);
- lock->expires = jiffies + timeout;
- lock->flags |= WAKE_LOCK_AUTO_EXPIRE;
- list_add_tail(&lock->link, &active_wake_locks[type]);
- } else {
- if (debug_mask & DEBUG_WAKE_LOCK)
- pr_info("wake_lock: %s, type %d\n", lock->name, type);
- lock->expires = LONG_MAX;
- lock->flags &= ~WAKE_LOCK_AUTO_EXPIRE;
- list_add(&lock->link, &active_wake_locks[type]);
- }
- if (type == WAKE_LOCK_SUSPEND) {
- current_event_num++;
-#ifdef CONFIG_WAKELOCK_STAT
- if (lock == &main_wake_lock)
- update_sleep_wait_stats_locked(1);
- else if (!wake_lock_active(&main_wake_lock))
- update_sleep_wait_stats_locked(0);
-#endif
- if (has_timeout)
- expire_in = has_wake_lock_locked(type);
- else
- expire_in = -1;
- if (expire_in > 0) {
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("wake_lock: %s, start expire timer, "
- "%ld\n", lock->name, expire_in);
- mod_timer(&expire_timer, jiffies + expire_in);
- } else {
- if (del_timer(&expire_timer))
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("wake_lock: %s, stop expire timer\n",
- lock->name);
- if (expire_in == 0)
- queue_work(suspend_work_queue, &suspend_work);
- }
- }
- spin_unlock_irqrestore(&list_lock, irqflags);
-}
-
-void wake_lock(struct wake_lock *lock)
-{
- wake_lock_internal(lock, 0, 0);
-}
-EXPORT_SYMBOL(wake_lock);
-
-void wake_lock_timeout(struct wake_lock *lock, long timeout)
-{
- wake_lock_internal(lock, timeout, 1);
-}
-EXPORT_SYMBOL(wake_lock_timeout);
-
-void wake_unlock(struct wake_lock *lock)
-{
- int type;
- unsigned long irqflags;
- spin_lock_irqsave(&list_lock, irqflags);
- type = lock->flags & WAKE_LOCK_TYPE_MASK;
-#ifdef CONFIG_WAKELOCK_STAT
- wake_unlock_stat_locked(lock, 0);
-#endif
- if (debug_mask & DEBUG_WAKE_LOCK)
- pr_info("wake_unlock: %s\n", lock->name);
- lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
- list_del(&lock->link);
- list_add(&lock->link, &inactive_locks);
- if (type == WAKE_LOCK_SUSPEND) {
- long has_lock = has_wake_lock_locked(type);
- if (has_lock > 0) {
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("wake_unlock: %s, start expire timer, "
- "%ld\n", lock->name, has_lock);
- mod_timer(&expire_timer, jiffies + has_lock);
- } else {
- if (del_timer(&expire_timer))
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("wake_unlock: %s, stop expire "
- "timer\n", lock->name);
- if (has_lock == 0)
- queue_work(suspend_work_queue, &suspend_work);
- }
- if (lock == &main_wake_lock) {
- if (debug_mask & DEBUG_SUSPEND)
- print_active_locks(WAKE_LOCK_SUSPEND);
-#ifdef CONFIG_WAKELOCK_STAT
- update_sleep_wait_stats_locked(0);
-#endif
- }
- }
- spin_unlock_irqrestore(&list_lock, irqflags);
-}
-EXPORT_SYMBOL(wake_unlock);
-
-int wake_lock_active(struct wake_lock *lock)
-{
- return !!(lock->flags & WAKE_LOCK_ACTIVE);
-}
-EXPORT_SYMBOL(wake_lock_active);
-
-static int wakelock_stats_open(struct inode *inode, struct file *file)
-{
- return single_open(file, wakelock_stats_show, NULL);
-}
-
-static const struct file_operations wakelock_stats_fops = {
- .owner = THIS_MODULE,
- .open = wakelock_stats_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int __init wakelocks_init(void)
-{
- int ret;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(active_wake_locks); i++)
- INIT_LIST_HEAD(&active_wake_locks[i]);
-
-#ifdef CONFIG_WAKELOCK_STAT
- wake_lock_init(&deleted_wake_locks, WAKE_LOCK_SUSPEND,
- "deleted_wake_locks");
-#endif
- wake_lock_init(&main_wake_lock, WAKE_LOCK_SUSPEND, "main");
- wake_lock(&main_wake_lock);
- wake_lock_init(&unknown_wakeup, WAKE_LOCK_SUSPEND, "unknown_wakeups");
- wake_lock_init(&suspend_backoff_lock, WAKE_LOCK_SUSPEND,
- "suspend_backoff");
-
- ret = platform_device_register(&power_device);
- if (ret) {
- pr_err("wakelocks_init: platform_device_register failed\n");
- goto err_platform_device_register;
- }
- ret = platform_driver_register(&power_driver);
- if (ret) {
- pr_err("wakelocks_init: platform_driver_register failed\n");
- goto err_platform_driver_register;
- }
-
- INIT_COMPLETION(suspend_sys_sync_comp);
- suspend_sys_sync_work_queue =
- create_singlethread_workqueue("suspend_sys_sync");
- if (suspend_sys_sync_work_queue == NULL) {
- ret = -ENOMEM;
- goto err_suspend_sys_sync_work_queue;
- }
-
- suspend_work_queue = create_singlethread_workqueue("suspend");
- if (suspend_work_queue == NULL) {
- ret = -ENOMEM;
- goto err_suspend_work_queue;
- }
-
-#ifdef CONFIG_WAKELOCK_STAT
- proc_create("wakelocks", S_IRUGO, NULL, &wakelock_stats_fops);
-#endif
-
- return 0;
-
-err_suspend_work_queue:
-err_suspend_sys_sync_work_queue:
- platform_driver_unregister(&power_driver);
-err_platform_driver_register:
- platform_device_unregister(&power_device);
-err_platform_device_register:
- wake_lock_destroy(&suspend_backoff_lock);
- wake_lock_destroy(&unknown_wakeup);
- wake_lock_destroy(&main_wake_lock);
-#ifdef CONFIG_WAKELOCK_STAT
- wake_lock_destroy(&deleted_wake_locks);
-#endif
- return ret;
-}
-
-static void __exit wakelocks_exit(void)
-{
-#ifdef CONFIG_WAKELOCK_STAT
- remove_proc_entry("wakelocks", NULL);
-#endif
- destroy_workqueue(suspend_work_queue);
- destroy_workqueue(suspend_sys_sync_work_queue);
- platform_driver_unregister(&power_driver);
- platform_device_unregister(&power_device);
- wake_lock_destroy(&suspend_backoff_lock);
- wake_lock_destroy(&unknown_wakeup);
- wake_lock_destroy(&main_wake_lock);
-#ifdef CONFIG_WAKELOCK_STAT
- wake_lock_destroy(&deleted_wake_locks);
-#endif
-}
-
-core_initcall(wakelocks_init);
-module_exit(wakelocks_exit);
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 50f73be..7ffcc1b 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -543,7 +543,6 @@
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
conn->conn_valid = true;
spin_lock_init(&conn->lock);
- wake_lock_init(&conn->idle_lock, WAKE_LOCK_SUSPEND, "bt_idle");
switch (type) {
case ACL_LINK:
@@ -621,7 +620,6 @@
/* Make sure no timers are running */
del_timer(&conn->idle_timer);
- wake_lock_destroy(&conn->idle_lock);
del_timer(&conn->disc_timer);
del_timer(&conn->smp_timer);
__cancel_delayed_work(&conn->rssi_update_work);
@@ -1082,7 +1080,6 @@
if (conn->conn_valid) {
mod_timer(&conn->idle_timer,
jiffies + msecs_to_jiffies(hdev->idle_timeout));
- wake_lock(&conn->idle_lock);
}
spin_unlock_bh(&conn->lock);
}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 198773c..d243646 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2596,9 +2596,6 @@
else
conn->power_save = 0;
}
- if (conn->mode == HCI_CM_SNIFF)
- if (wake_lock_active(&conn->idle_lock))
- wake_unlock(&conn->idle_lock);
if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend))
hci_sco_setup(conn, ev->status);
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 5190c0b..b57532d 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -736,7 +736,6 @@
}
#if IS_ENABLED(CONFIG_IPV6)
else if (skb->protocol == htons(ETH_P_IPV6)) {
- struct neighbour *neigh = dst_get_neighbour(skb_dst(skb));
const struct in6_addr *addr6;
struct neighbour *neigh;
bool do_tx_error_icmp;
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index af268bd..f4ea679 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -83,6 +83,7 @@
AIF2_CAP,
AIF3_PB,
AIF3_CAP,
+ AIF4_VIFEED,
NUM_CODEC_DAIS,
};
@@ -2671,6 +2672,7 @@
{"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
{"AIF2 CAP", NULL, "AIF2_CAP Mixer"},
{"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
+ {"AIF4 VI", NULL, "SPK_OUT"},
/* SLIM_MIXER("AIF1_CAP Mixer"),*/
{"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
@@ -3143,6 +3145,7 @@
{"MIC BIAS3 Internal2", NULL, "LDO_H"},
{"MIC BIAS3 External", NULL, "LDO_H"},
{"MIC BIAS4 External", NULL, "LDO_H"},
+
};
static int taiko_readable(struct snd_soc_codec *ssc, unsigned int reg)
@@ -3367,6 +3370,7 @@
unsigned int rx_num, unsigned int *rx_slot)
{
+ struct wcd9xxx_codec_dai_data *dai_data = NULL;
struct taiko_priv *taiko = snd_soc_codec_get_drvdata(dai->codec);
struct wcd9xxx *core = dev_get_drvdata(dai->codec->dev->parent);
if (!tx_slot && !rx_slot) {
@@ -3378,9 +3382,18 @@
__func__, dai->name, dai->id, tx_num, rx_num,
taiko->intf_type);
- if (taiko->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ if (taiko->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
wcd9xxx_init_slimslave(core, core->slim->laddr,
- tx_num, tx_slot, rx_num, rx_slot);
+ tx_num, tx_slot, rx_num, rx_slot);
+ /*Reserve tx11 and tx12 for VI feedback path*/
+ dai_data = &taiko->dai[AIF4_VIFEED];
+ if (dai_data) {
+ list_add_tail(&core->tx_chs[TAIKO_TX11].list,
+ &dai_data->wcd9xxx_ch_list);
+ list_add_tail(&core->tx_chs[TAIKO_TX12].list,
+ &dai_data->wcd9xxx_ch_list);
+ }
+ }
return 0;
}
@@ -3414,6 +3427,7 @@
case AIF1_CAP:
case AIF2_CAP:
case AIF3_CAP:
+ case AIF4_VIFEED:
if (!tx_slot || !tx_num) {
pr_err("%s: Invalid tx_slot %d or tx_num %d\n",
__func__, (u32) tx_slot, (u32) tx_num);
@@ -3639,12 +3653,14 @@
switch (substream->stream) {
case SNDRV_PCM_STREAM_CAPTURE:
- ret = taiko_set_decimator_rate(dai, tx_fs_rate,
- params_rate(params));
- if (ret < 0) {
- pr_err("%s: set decimator rate failed %d\n", __func__,
- ret);
- return ret;
+ if (dai->id != AIF4_VIFEED) {
+ ret = taiko_set_decimator_rate(dai, tx_fs_rate,
+ params_rate(params));
+ if (ret < 0) {
+ pr_err("%s: set decimator rate failed %d\n",
+ __func__, ret);
+ return ret;
+ }
}
if (taiko->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
@@ -3828,6 +3844,20 @@
},
.ops = &taiko_dai_ops,
},
+ {
+ .name = "taiko_vifeedback",
+ .id = AIF4_VIFEED,
+ .capture = {
+ .stream_name = "VIfeed",
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = TAIKO_FORMATS,
+ .rate_max = 48000,
+ .rate_min = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ },
+ .ops = &taiko_dai_ops,
+ },
};
static struct snd_soc_dai_driver taiko_i2s_dai[] = {
@@ -3967,6 +3997,89 @@
return ret;
}
+static int taiko_codec_enable_slimvi_feedback(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct wcd9xxx *core = NULL;
+ struct snd_soc_codec *codec = NULL;
+ struct taiko_priv *taiko_p = NULL;
+ u32 ret = 0;
+ struct wcd9xxx_codec_dai_data *dai = NULL;
+
+ if (!w || !w->codec) {
+ pr_err("%s invalid params\n", __func__);
+ return -EINVAL;
+ }
+ codec = w->codec;
+ taiko_p = snd_soc_codec_get_drvdata(codec);
+ core = dev_get_drvdata(codec->dev->parent);
+
+ pr_debug("%s: event called! codec name %s num_dai %d stream name %s\n",
+ __func__, w->codec->name, w->codec->num_dai, w->sname);
+
+ /* Execute the callback only if interface type is slimbus */
+ if (taiko_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ pr_err("%s Interface is not correct", __func__);
+ return 0;
+ }
+
+ pr_debug("%s(): w->name %s event %d w->shift %d\n",
+ __func__, w->name, event, w->shift);
+ if (w->shift != AIF4_VIFEED) {
+ pr_err("%s Error in enabling the tx path\n", __func__);
+ ret = -EINVAL;
+ goto out_vi;
+ }
+ dai = &taiko_p->dai[w->shift];
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /*Enable Clip Detection*/
+ snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_CLIP_DET,
+ 0x8, 0x8);
+ /*Enable V&I sensing*/
+ snd_soc_update_bits(codec, TAIKO_A_SPKR_PROT_EN,
+ 0x88, 0x88);
+ /*Enable spkr VI clocks*/
+ snd_soc_update_bits(codec,
+ TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0xC, 0xC);
+ /*Enable Voltage Decimator*/
+ snd_soc_update_bits(codec,
+ TAIKO_A_CDC_CONN_TX_SB_B9_CTL, 0x1F, 0x12);
+ /*Enable Current Decimator*/
+ snd_soc_update_bits(codec,
+ TAIKO_A_CDC_CONN_TX_SB_B10_CTL, 0x1F, 0x13);
+ ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
+ dai->rate, dai->bit_width,
+ &dai->grph);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
+ dai->grph);
+ if (ret)
+ pr_err("%s error in close_slim_sch_tx %d\n",
+ __func__, ret);
+ /*Disable Voltage decimator*/
+ snd_soc_update_bits(codec,
+ TAIKO_A_CDC_CONN_TX_SB_B9_CTL, 0x1F, 0x0);
+ /*Disable Current decimator*/
+ snd_soc_update_bits(codec,
+ TAIKO_A_CDC_CONN_TX_SB_B10_CTL, 0x1F, 0x0);
+ /*Disable spkr VI clocks*/
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL,
+ 0xC, 0x0);
+ /*Disable V&I sensing*/
+ snd_soc_update_bits(codec, TAIKO_A_SPKR_PROT_EN,
+ 0x88, 0x00);
+ /*Disable clip detection*/
+ snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_CLIP_DET,
+ 0x8, 0x0);
+ break;
+ }
+out_vi:
+ return ret;
+}
+
static int taiko_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
@@ -4440,6 +4553,10 @@
AIF3_CAP, 0, taiko_codec_enable_slimtx,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_OUT_E("AIF4 VI", "VIfeed", 0, SND_SOC_NOPM,
+ AIF4_VIFEED, 0, taiko_codec_enable_slimvi_feedback,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
@@ -4529,7 +4646,6 @@
SND_SOC_DAPM_MIXER("LINEOUT4_PA_MIXER", SND_SOC_NOPM, 0, 0,
lineout4_pa_mix, ARRAY_SIZE(lineout4_pa_mix)),
-
};
static irqreturn_t taiko_slimbus_irq(int irq, void *data)
diff --git a/sound/soc/codecs/wcd9xxx-common.c b/sound/soc/codecs/wcd9xxx-common.c
index f1b6203..916ff1a 100644
--- a/sound/soc/codecs/wcd9xxx-common.c
+++ b/sound/soc/codecs/wcd9xxx-common.c
@@ -139,7 +139,7 @@
if (on && (++cp_count == 1)) {
snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
0x01, 0x01);
- dev_info(codec->dev, "%s: Charge Pump enabled, count = %d\n",
+ dev_dbg(codec->dev, "%s: Charge Pump enabled, count = %d\n",
__func__, cp_count);
}
@@ -149,7 +149,7 @@
__func__);
if (snd_soc_read(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL)
& 0x01) {
- dev_info(codec->dev, "%s: Actual chargepump is ON\n",
+ dev_dbg(codec->dev, "%s: Actual chargepump is ON\n",
__func__);
}
cp_count = 0;
@@ -526,7 +526,7 @@
(*clsh_state_fp[new_state]) (codec, cdc_clsh_d,
req_state, req_type);
cdc_clsh_d->state = new_state;
- dev_info(codec->dev, "%s: ClassH state transition from %s to %s\n",
+ dev_dbg(codec->dev, "%s: ClassH state transition from %s to %s\n",
__func__, state_to_str(old_state),
state_to_str(cdc_clsh_d->state));
@@ -546,7 +546,7 @@
(*clsh_state_fp[new_state]) (codec, cdc_clsh_d,
req_state, req_type);
cdc_clsh_d->state = new_state;
- dev_info(codec->dev, "%s: ClassH state transition from %s to %s\n",
+ dev_dbg(codec->dev, "%s: ClassH state transition from %s to %s\n",
__func__, state_to_str(old_state),
state_to_str(cdc_clsh_d->state));
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 39afb73..4e6cbaa 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -788,7 +788,7 @@
runtime->private_data = compr;
atomic_set(&prtd->eos, 0);
compressed_audio.prtd = &compr->prtd;
- ret = compressed_set_volume(compressed_audio.volume);
+ ret = compressed_set_volume(0);
if (ret < 0)
pr_err("%s : Set Volume failed : %d", __func__, ret);
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 4462213..747e027 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -1802,13 +1802,13 @@
.name = LPASS_BE_SLIMBUS_4_TX,
.stream_name = "Slimbus4 Capture",
.cpu_dai_name = "msm-dai-q6-dev.16393",
- .platform_name = "msm-pcm-routing",
+ .platform_name = "msm-pcm-hostless",
.codec_name = "taiko_codec",
- .codec_dai_name = "taiko_tx1",
- .no_pcm = 1,
+ .codec_dai_name = "taiko_vifeedback",
.be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
.ops = &msm8974_be_ops,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
},
/* Incall Record Uplink BACK END DAI Link */
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index b71132e..ccaf39d 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -85,6 +85,9 @@
atomic64_t paddr;
atomic64_t kvaddr;
atomic64_t mem_len;
+
+ /* Speaker protection */
+ struct msm_spk_prot_cfg spk_prot_cfg;
};
static struct acdb_data acdb_data;
@@ -767,6 +770,34 @@
done:
return;
}
+void get_spk_protection_cfg(struct msm_spk_prot_cfg *prot_cfg)
+{
+ mutex_lock(&acdb_data.acdb_mutex);
+ if (prot_cfg) {
+ prot_cfg->mode = acdb_data.spk_prot_cfg.mode;
+ prot_cfg->r0 = acdb_data.spk_prot_cfg.r0;
+ prot_cfg->t0 = acdb_data.spk_prot_cfg.t0;
+ } else
+ pr_err("%s prot_cfg is NULL\n", __func__);
+ mutex_unlock(&acdb_data.acdb_mutex);
+}
+static void get_spk_protection_status(struct msm_spk_prot_status *status)
+{
+ /*Call AFE function here to query the status*/
+ struct afe_spkr_prot_get_vi_calib calib_resp;
+ if (status) {
+ status->status = -EINVAL;
+ if (!afe_spk_prot_get_calib_data(&calib_resp)) {
+ if (calib_resp.res_cfg.th_vi_ca_state == 1)
+ status->status = -EAGAIN;
+ else if (calib_resp.res_cfg.th_vi_ca_state == 2) {
+ status->status = 0;
+ status->r0 = calib_resp.res_cfg.r0_cali_q24;
+ }
+ }
+ } else
+ pr_err("%s invalid params\n", __func__);
+}
static int acdb_open(struct inode *inode, struct file *f)
{
@@ -880,6 +911,8 @@
int32_t map_fd;
uint32_t topology;
uint32_t data[MAX_IOCTL_DATA];
+ struct msm_spk_prot_status prot_status;
+ struct msm_spk_prot_status acdb_spk_status;
pr_debug("%s\n", __func__);
switch (cmd) {
@@ -943,6 +976,43 @@
}
store_asm_topology(topology);
goto done;
+ case AUDIO_SET_SPEAKER_PROT:
+ mutex_lock(&acdb_data.acdb_mutex);
+ if (copy_from_user(&acdb_data.spk_prot_cfg, (void *)arg,
+ sizeof(acdb_data.spk_prot_cfg))) {
+ pr_err("%s fail to copy spk_prot_cfg\n", __func__);
+ result = -EFAULT;
+ }
+ mutex_unlock(&acdb_data.acdb_mutex);
+ goto done;
+ case AUDIO_GET_SPEAKER_PROT:
+ mutex_lock(&acdb_data.acdb_mutex);
+ /*Indicates calibration was succesfull*/
+ if (!acdb_data.spk_prot_cfg.mode) {
+ prot_status.r0 = acdb_data.spk_prot_cfg.r0;
+ prot_status.status = 0;
+ } else if (acdb_data.spk_prot_cfg.mode == 1) {
+ /*Call AFE to query the status*/
+ acdb_spk_status.status = -EINVAL;
+ acdb_spk_status.r0 = -1;
+ get_spk_protection_status(&acdb_spk_status);
+ prot_status.r0 = acdb_spk_status.r0;
+ prot_status.status = acdb_spk_status.status;
+ if (!acdb_spk_status.status) {
+ acdb_data.spk_prot_cfg.mode = 0;
+ acdb_data.spk_prot_cfg.r0 = prot_status.r0;
+ }
+ } else {
+ /*Indicates calibration data is invalid*/
+ prot_status.status = -EINVAL;
+ prot_status.r0 = -1;
+ }
+ if (copy_to_user((void *)arg, &prot_status,
+ sizeof(prot_status))) {
+ pr_err("%s Failed to update prot_status\n", __func__);
+ }
+ mutex_unlock(&acdb_data.acdb_mutex);
+ goto done;
}
if (copy_from_user(&size, (void *) arg, sizeof(size))) {
@@ -1110,6 +1180,8 @@
static int __init acdb_init(void)
{
memset(&acdb_data, 0, sizeof(acdb_data));
+ /*Speaker protection disabled*/
+ acdb_data.spk_prot_cfg.mode = -1;
mutex_init(&acdb_data.acdb_mutex);
atomic_set(&usage_count, 0);
atomic_set(&acdb_data.valid_adm_custom_top, 1);
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.h b/sound/soc/msm/qdsp6v2/audio_acdb.h
index 0b6110d..4834855 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.h
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.h
@@ -63,5 +63,6 @@
void get_vocstrm_cal(struct acdb_cal_block *cal_block);
void get_vocvol_cal(struct acdb_cal_block *cal_block);
void get_sidetone_cal(struct sidetone_cal *cal_data);
+void get_spk_protection_cfg(struct msm_spk_prot_cfg *prot_cfg);
#endif
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index d0b5500..f6e571b8 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -754,7 +754,7 @@
prtd->session_id,
substream->stream);
- ret = compressed_set_volume(compressed_audio.volume);
+ ret = compressed_set_volume(0);
if (ret < 0)
pr_err("%s : Set Volume failed : %d", __func__, ret);
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index c300a9f..557ec65 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -485,6 +485,7 @@
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
+ case SNDRV_PCM_FMTBIT_SPECIAL:
dai_data->port_config.i2s.bit_width = 16;
break;
case SNDRV_PCM_FORMAT_S24_LE:
@@ -560,6 +561,7 @@
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
+ case SNDRV_PCM_FMTBIT_SPECIAL:
dai_data->port_config.slim_sch.bit_width = 16;
break;
case SNDRV_PCM_FORMAT_S24_LE:
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index e05e58d..4ca96d7 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -459,19 +459,20 @@
pr_debug("%s\n", __func__);
- dir = IN;
- ret = wait_event_timeout(the_locks.eos_wait,
- prtd->cmd_ack, 5 * HZ);
- if (ret < 0)
- pr_err("%s: CMD_EOS failed\n", __func__);
- q6asm_cmd(prtd->audio_client, CMD_CLOSE);
- q6asm_audio_client_buf_free_contiguous(dir,
- prtd->audio_client);
-
+ if (prtd->audio_client) {
+ dir = IN;
+ ret = wait_event_timeout(the_locks.eos_wait,
+ prtd->cmd_ack, 5 * HZ);
+ if (ret < 0)
+ pr_err("%s: CMD_EOS failed\n", __func__);
+ q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+ q6asm_audio_client_buf_free_contiguous(dir,
+ prtd->audio_client);
+ pcm_audio.prtd = NULL;
+ q6asm_audio_client_free(prtd->audio_client);
+ }
msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
SNDRV_PCM_STREAM_PLAYBACK);
- pcm_audio.prtd = NULL;
- q6asm_audio_client_free(prtd->audio_client);
kfree(prtd);
return 0;
}
@@ -678,7 +679,7 @@
if (ret < 0) {
pr_err("%s: q6asm_open_write_v2 failed\n", __func__);
q6asm_audio_client_free(prtd->audio_client);
- kfree(prtd);
+ prtd->audio_client = NULL;
return -ENOMEM;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 02c3457..9fe438c 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -2004,6 +2004,60 @@
msm_routing_put_eq_band_audio_mixer),
};
+static int spkr_prot_put_vi_lch_port(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ int item;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ pr_debug("%s item is %d\n", __func__,
+ ucontrol->value.enumerated.item[0]);
+ mutex_lock(&routing_lock);
+ item = ucontrol->value.enumerated.item[0];
+ if (item < e->max) {
+ pr_debug("%s RX DAI ID %d TX DAI id %d\n",
+ __func__, e->shift_l , e->values[item]);
+ if (e->shift_l < MSM_BACKEND_DAI_MAX &&
+ e->values[item] < MSM_BACKEND_DAI_MAX)
+ ret = afe_spk_prot_feed_back_cfg(
+ msm_bedais[e->values[item]].port_id,
+ msm_bedais[e->shift_l].port_id, 1, 0);
+ else {
+ pr_err("%s values are out of range\n", __func__);
+ ret = -EINVAL;
+ }
+ } else {
+ pr_err("%s item value is out of range\n", __func__);
+ ret = -EINVAL;
+ }
+ mutex_unlock(&routing_lock);
+ return ret;
+}
+
+static int spkr_prot_get_vi_lch_port(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s\n", __func__);
+ return 0;
+}
+
+static const char * const slim0_rx_vi_fb_tx_lch_mux_text[] = {
+ "SLIM4_TX",
+};
+
+static const int const slim0_rx_vi_fb_tx_lch_value[] = {
+ MSM_BACKEND_DAI_SLIMBUS_4_TX,
+};
+static const struct soc_enum slim0_rx_vi_fb_lch_mux_enum =
+ SOC_VALUE_ENUM_DOUBLE(0, MSM_BACKEND_DAI_SLIMBUS_0_RX, 0, 0,
+ ARRAY_SIZE(slim0_rx_vi_fb_tx_lch_mux_text),
+ slim0_rx_vi_fb_tx_lch_mux_text, slim0_rx_vi_fb_tx_lch_value);
+
+static const struct snd_kcontrol_new slim0_rx_vi_fb_lch_mux =
+ SOC_DAPM_ENUM_EXT("SLIM0_RX_VI_FB_LCH_MUX",
+ slim0_rx_vi_fb_lch_mux_enum, spkr_prot_get_vi_lch_port,
+ spkr_prot_put_vi_lch_port);
+
static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
/* Frontend AIF */
/* Widget name equals to Front-End DAI name<Need confirmation>,
@@ -2249,6 +2303,9 @@
SND_SOC_DAPM_OUTPUT("BE_OUT"),
SND_SOC_DAPM_INPUT("BE_IN"),
+ SND_SOC_DAPM_MUX("SLIM0_RX_VI_FB_LCH_MUX", SND_SOC_NOPM, 0, 0,
+ &slim0_rx_vi_fb_lch_mux),
+
};
static const struct snd_soc_dapm_route intercon[] = {
@@ -2554,7 +2611,9 @@
{"AUX_PCM_TX", NULL, "BE_IN"},
{"INCALL_RECORD_TX", NULL, "BE_IN"},
{"INCALL_RECORD_RX", NULL, "BE_IN"},
- {"BE_OUT", NULL, "VOICE_PLAYBACK_TX"}
+ {"BE_OUT", NULL, "VOICE_PLAYBACK_TX"},
+ {"SLIM0_RX_VI_FB_LCH_MUX", "SLIM4_TX", "SLIMBUS_4_TX"},
+ {"SLIMBUS_0_RX", NULL, "SLIM0_RX_VI_FB_LCH_MUX"},
};
static int msm_pcm_routing_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 1b5ad17..5e1da59 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -25,7 +25,6 @@
#include "audio_acdb.h"
-
struct afe_ctl {
void *apr;
atomic_t state;
@@ -44,6 +43,8 @@
atomic_t mem_map_cal_handles[MAX_AUDPROC_TYPES];
atomic_t mem_map_cal_index;
u16 dtmf_gen_rx_portid;
+ struct afe_spkr_prot_calib_get_resp calib_data;
+ int vi_tx_port;
};
static struct afe_ctl this_afe;
@@ -56,6 +57,10 @@
static int32_t afe_callback(struct apr_client_data *data, void *priv)
{
+ if (!data) {
+ pr_err("%s: Invalid param data\n", __func__);
+ return -EINVAL;
+ }
if (data->opcode == RESET_EVENTS) {
pr_debug("q6afe: reset event = %d %d apr[%p]\n",
data->reset_event, data->reset_proc, this_afe.apr);
@@ -69,11 +74,30 @@
this_afe.task->comm, this_afe.task->pid);
return 0;
}
- pr_debug("%s:opcode = 0x%x cmd = 0x%x status = 0x%x\n",
- __func__, data->opcode,
- ((uint32_t *)(data->payload))[0],
- ((uint32_t *)(data->payload))[1]);
- if (data->payload_size) {
+ pr_debug("%s:opcode = 0x%x cmd = 0x%x status = 0x%x size = %d\n",
+ __func__, data->opcode,
+ ((uint32_t *)(data->payload))[0],
+ ((uint32_t *)(data->payload))[1],
+ data->payload_size);
+ if (data->opcode == AFE_PORT_CMDRSP_GET_PARAM_V2) {
+ u8 *payload = data->payload;
+ if ((data->payload_size < sizeof(this_afe.calib_data))
+ || !payload || (data->token >= AFE_MAX_PORTS)) {
+ pr_err("%s size %d payload %p token %d\n",
+ __func__, data->payload_size, payload, data->token);
+ return -EINVAL;
+ }
+ memcpy(&this_afe.calib_data, payload,
+ sizeof(this_afe.calib_data));
+ if (!this_afe.calib_data.status) {
+ atomic_set(&this_afe.state, 0);
+ pr_err("%s rest %d state %x\n" , __func__
+ , this_afe.calib_data.res_cfg.r0_cali_q24,
+ this_afe.calib_data.res_cfg.th_vi_ca_state);
+ } else
+ atomic_set(&this_afe.state, -1);
+ wake_up(&this_afe.wait[data->token]);
+ } else if (data->payload_size) {
uint32_t *payload;
uint16_t port_id = 0;
payload = data->payload;
@@ -346,14 +370,140 @@
return;
}
+static int afe_spk_prot_prepare(int port, int param_id,
+ union afe_spkr_prot_config *prot_config)
+{
+ int ret = -EINVAL;
+ int index = 0;
+ struct afe_spkr_prot_config_command config;
+
+ if (!prot_config) {
+ pr_err("%s Invalid params\n", __func__);
+ goto fail_cmd;
+ }
+ if ((q6audio_validate_port(port) < 0)) {
+ pr_err("%s invalid port %d", __func__, port);
+ goto fail_cmd;
+ }
+ memset(&config, 0 , sizeof(config));
+ index = q6audio_get_port_index(port);
+ switch (param_id) {
+ case AFE_PARAM_ID_FBSP_MODE_RX_CFG:
+ config.pdata.module_id = AFE_MODULE_FB_SPKR_PROT_RX;
+ break;
+ case AFE_PARAM_ID_FEEDBACK_PATH_CFG:
+ this_afe.vi_tx_port = port;
+ case AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG:
+ case AFE_PARAM_ID_MODE_VI_PROC_CFG:
+ config.pdata.module_id = AFE_MODULE_FB_SPKR_PROT_VI_PROC;
+ break;
+ default:
+ goto fail_cmd;
+ break;
+ }
+
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = index;
+
+ config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ config.param.port_id = q6audio_get_port_id(port);
+ config.param.payload_size = sizeof(config) - sizeof(config.hdr)
+ - sizeof(config.param);
+ config.pdata.param_id = param_id;
+ config.pdata.param_size = sizeof(config.prot_config);
+ config.prot_config = *prot_config;
+ atomic_set(&this_afe.state, 1);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
+ if (ret < 0) {
+ pr_err("%s: Setting param for port %d param[0x%x]failed\n",
+ __func__, port, param_id);
+ goto fail_cmd;
+ }
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ if (atomic_read(&this_afe.status) != 0) {
+ pr_err("%s: config cmd failed\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ ret = 0;
+fail_cmd:
+ pr_err("%s config.pdata.param_id %x status %d\n",
+ __func__, config.pdata.param_id, ret);
+ return ret;
+}
+
+static void afe_send_cal_spkr_prot_tx(int port_id)
+{
+ struct msm_spk_prot_cfg prot_cfg;
+ union afe_spkr_prot_config afe_spk_config;
+
+ /*Get spkr protection cfg data*/
+ get_spk_protection_cfg(&prot_cfg);
+
+ if ((!prot_cfg.mode || prot_cfg.mode == 1) &&
+ (this_afe.vi_tx_port == port_id)) {
+ afe_spk_config.mode_rx_cfg.minor_version = 1;
+ afe_spk_config.mode_rx_cfg.mode =
+ (uint32_t)prot_cfg.mode;
+ if (afe_spk_prot_prepare(port_id,
+ AFE_PARAM_ID_MODE_VI_PROC_CFG,
+ &afe_spk_config))
+ pr_err("%s TX VI_PROC_CFG failed\n", __func__);
+ afe_spk_config.vi_proc_cfg.minor_version = 1;
+ afe_spk_config.vi_proc_cfg.r0_cali_q24 =
+ (uint32_t) prot_cfg.r0;
+ afe_spk_config.vi_proc_cfg.t0_cali_q6 =
+ (uint32_t) prot_cfg.t0;
+ if (afe_spk_prot_prepare(port_id,
+ AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG,
+ &afe_spk_config))
+ pr_err("%s SPKR_CALIB_VI_PROC_CFG failed\n",
+ __func__);
+ }
+}
+
+static void afe_send_cal_spkr_prot_rx(int port_id)
+{
+ struct msm_spk_prot_cfg prot_cfg;
+ union afe_spkr_prot_config afe_spk_config;
+
+ /*Get spkr protection cfg data*/
+ get_spk_protection_cfg(&prot_cfg);
+
+ if (!prot_cfg.mode || prot_cfg.mode == 1) {
+ afe_spk_config.mode_rx_cfg.mode =
+ (uint32_t)prot_cfg.mode;
+ afe_spk_config.mode_rx_cfg.minor_version = 1;
+ if (afe_spk_prot_prepare(port_id,
+ AFE_PARAM_ID_FBSP_MODE_RX_CFG,
+ &afe_spk_config))
+ pr_err("%s RX MODE_VI_PROC_CFG failed\n",
+ __func__);
+ }
+}
+
void afe_send_cal(u16 port_id)
{
pr_debug("%s\n", __func__);
- if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX)
+ if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX) {
+ afe_send_cal_spkr_prot_tx(port_id);
afe_send_cal_block(TX_CAL, port_id);
- else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX)
+ } else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX) {
+ afe_send_cal_spkr_prot_rx(port_id);
afe_send_cal_block(RX_CAL, port_id);
+ }
}
int afe_port_start(u16 port_id, union afe_port_config *afe_config,
@@ -2299,6 +2449,107 @@
return ret;
}
+int afe_spk_prot_get_calib_data(struct afe_spkr_prot_get_vi_calib *calib_resp)
+{
+ int ret = -EINVAL;
+ int index = 0, port = SLIMBUS_4_TX;
+
+ if (!calib_resp) {
+ pr_err("%s Invalid params\n", __func__);
+ goto fail_cmd;
+ }
+ if ((q6audio_validate_port(port) < 0)) {
+ pr_err("%s invalid port %d\n", __func__, port);
+ goto fail_cmd;
+ }
+ index = q6audio_get_port_index(port);
+ calib_resp->get_param.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ calib_resp->get_param.hdr.pkt_size = sizeof(*calib_resp);
+ calib_resp->get_param.hdr.src_port = 0;
+ calib_resp->get_param.hdr.dest_port = 0;
+ calib_resp->get_param.hdr.token = index;
+ calib_resp->get_param.hdr.opcode = AFE_PORT_CMD_GET_PARAM_V2;
+ calib_resp->get_param.mem_map_handle = 0;
+ calib_resp->get_param.module_id = AFE_MODULE_FB_SPKR_PROT_VI_PROC;
+ calib_resp->get_param.param_id = AFE_PARAM_ID_CALIB_RES_CFG;
+ calib_resp->get_param.payload_address_lsw = 0;
+ calib_resp->get_param.payload_address_msw = 0;
+ calib_resp->get_param.payload_size = sizeof(*calib_resp)
+ - sizeof(calib_resp->get_param);
+ calib_resp->get_param.port_id = q6audio_get_port_id(port);
+ calib_resp->pdata.module_id = AFE_MODULE_FB_SPKR_PROT_VI_PROC;
+ calib_resp->pdata.param_id = AFE_PARAM_ID_CALIB_RES_CFG;
+ calib_resp->pdata.param_size = sizeof(calib_resp->res_cfg);
+ atomic_set(&this_afe.state, 1);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *)calib_resp);
+ if (ret < 0) {
+ pr_err("%s: get param port %d param id[0x%x]failed\n",
+ __func__, port, calib_resp->get_param.param_id);
+ goto fail_cmd;
+ }
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ if (atomic_read(&this_afe.status) != 0) {
+ pr_err("%s: config cmd failed\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ memcpy(&calib_resp->res_cfg , &this_afe.calib_data.res_cfg,
+ sizeof(this_afe.calib_data.res_cfg));
+ pr_debug("%s state %d resistance %d\n", __func__,
+ calib_resp->res_cfg.th_vi_ca_state,
+ calib_resp->res_cfg.r0_cali_q24);
+ ret = 0;
+fail_cmd:
+ return ret;
+}
+
+int afe_spk_prot_feed_back_cfg(int src_port, int dst_port,
+ int l_ch, int r_ch)
+{
+ int ret = -EINVAL;
+ union afe_spkr_prot_config prot_config;
+ int index = 0;
+
+ if ((q6audio_validate_port(src_port) < 0) ||
+ (q6audio_validate_port(dst_port) < 0)) {
+ pr_err("%s invalid ports src %d dst %d",
+ __func__, src_port, dst_port);
+ goto fail_cmd;
+ }
+ if (!l_ch && !r_ch) {
+ pr_err("%s error ch values zero\n", __func__);
+ goto fail_cmd;
+ }
+ pr_debug("%s src_port %x dst_port %x l_ch %d r_ch %d\n",
+ __func__, src_port, dst_port, l_ch, r_ch);
+ memset(&prot_config, 0, sizeof(prot_config));
+ prot_config.feedback_path_cfg.dst_portid =
+ q6audio_get_port_id(dst_port);
+ if (l_ch) {
+ prot_config.feedback_path_cfg.chan_info[index++] = 1;
+ prot_config.feedback_path_cfg.chan_info[index++] = 2;
+ }
+ if (r_ch) {
+ prot_config.feedback_path_cfg.chan_info[index++] = 3;
+ prot_config.feedback_path_cfg.chan_info[index++] = 4;
+ }
+ prot_config.feedback_path_cfg.num_channels = index;
+ prot_config.feedback_path_cfg.minor_version = 1;
+ ret = afe_spk_prot_prepare(src_port,
+ AFE_PARAM_ID_FEEDBACK_PATH_CFG, &prot_config);
+fail_cmd:
+ return ret;
+}
+
static int __init afe_init(void)
{
int i = 0;
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 4e7455b..0549671 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -2344,7 +2344,7 @@
fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
sizeof(fmt.fmt_blk);
fmt.num_channels = channels;
- fmt.bits_per_sample = 16;
+ fmt.bits_per_sample = bits_per_sample;
fmt.sample_rate = rate;
fmt.is_signed = 1;
diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c
index 99cb6a6..4ed0fb7 100644
--- a/sound/soc/msm/qdsp6v2/q6audio-v2.c
+++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c
@@ -43,6 +43,7 @@
case SLIMBUS_1_TX: return IDX_SLIMBUS_1_TX;
case SLIMBUS_2_RX: return IDX_SLIMBUS_2_RX;
case SLIMBUS_2_TX: return IDX_SLIMBUS_2_TX;
+ case SLIMBUS_4_TX: return IDX_SLIMBUS_4_TX;
case INT_BT_SCO_RX: return IDX_INT_BT_SCO_RX;
case INT_BT_SCO_TX: return IDX_INT_BT_SCO_TX;
case INT_BT_A2DP_RX: return IDX_INT_BT_A2DP_RX;
@@ -89,6 +90,7 @@
case SLIMBUS_1_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_TX;
case SLIMBUS_2_RX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_RX;
case SLIMBUS_2_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_TX;
+ case SLIMBUS_4_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX;
case INT_BT_SCO_RX: return AFE_PORT_ID_INTERNAL_BT_SCO_RX;
case INT_BT_SCO_TX: return AFE_PORT_ID_INTERNAL_BT_SCO_TX;
case INT_BT_A2DP_RX: return AFE_PORT_ID_INTERNAL_BT_A2DP_RX;
@@ -182,6 +184,7 @@
case SLIMBUS_1_TX:
case SLIMBUS_2_RX:
case SLIMBUS_2_TX:
+ case SLIMBUS_4_TX:
case INT_BT_SCO_RX:
case INT_BT_SCO_TX:
case INT_BT_A2DP_RX: