Merge "msm: ipc: Change IPC log file name for IPC Router"
diff --git a/Documentation/devicetree/bindings/bif/qpnp-bsi.txt b/Documentation/devicetree/bindings/bif/qpnp-bsi.txt
new file mode 100644
index 0000000..29267dd
--- /dev/null
+++ b/Documentation/devicetree/bindings/bif/qpnp-bsi.txt
@@ -0,0 +1,91 @@
+Qualcomm QPNP BSI - battery serial interface devices
+
+qpnp-bsi is a BIF driver which supports the BSI peripheral inside of PMICs
+that utilize the MSM SPMI implementation.
+
+Required properties:
+- compatible: Must be "qcom,qpnp-bsi".
+- reg: Specifies the SPMI address and size for this BSI device as
+ well as the address of the BATT_ID status register.
+- reg-names: A list of strings identifying the reg property entries. The
+ list must contain both "bsi-base" and "batt-id-status".
+- label: A string used as a descriptive name for this BIF controller.
+- interrupts: Specifies a list of four interrupts corresponding to
+ IRQ ERR, IRQ RX, IRQ TX, and IRQ BATT_PRESENT in any order.
+- interrupt-names: Must be a list of strings containing all three of these
+ strings: "err", "rx", "tx", "batt-present". The ordering of
+ these strings must match the ordering of the interrupts in
+ the "interrupts" property.
+
+Required structure:
+- A qcom,qpnp-bsi node must be a child of an SPMI node that has specified the
+ spmi-slave-container property.
+
+Optional properties:
+- qcom,min-clock-period: This property specifies a minimum clock period for the
+ Tau BIF reference in nanoseconds. It can be used to
+ impose a minimum period which is higher (i.e. more
+ restrictive) than that supported by the hardware.
+ The BSI module supports 8 possible periods between
+ 2080 ns and 150420 ns.
+- qcom,max-clock-period: This property specifies a maximum clock period for the
+ Tau BIF reference in nanoseconds. It can be used to
+ impose a maximum period which is lower (i.e. more
+ restrictive) than that supported by the hardware.
+ The BSI module supports 8 possible periods between
+ 2080 ns and 150420 ns.
+- qcom,sample-rate: Specifies the rate at which the BIF BCL should be
+ sampled during communication with respect to the Tau
+ BIF reference rate. Supported values are 4 and 8
+ which represent 4x and 8x sampling rates
+ respectively. If this property is not specified,
+ then 4x sampling is assumed.
+- qcom,channel-num: VADC channel number associated PMIC BATT_ID pin. If
+ no channel is specified, then it will not be
+ possible to measure the slave Rid.
+- qcom,pullup-ohms: Host side pull-up resistance present on BCL in ohms.
+ If no value is specified, then 100000 ohms is
+ assumed.
+- qcom,vref-microvolts: Reference voltage used for BCL divider circuit in
+ microvolts. If no value is specified, then
+ 1800000 uV is assumed.
+
+All properties specified within for the BIF framework can also be used. These
+properties can be found in bif.txt.
+
+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,bsi@1b00 {
+ compatible = "qcom,qpnp-bsi";
+ reg = <0x1b00 0x100>,
+ <0x1208 0x1>;
+ reg-names = "bsi-base", "batt-id-status";
+ label = "pm8941-bsi";
+ interrupts = <0x0 0x1b 0x0>,
+ <0x0 0x1b 0x1>,
+ <0x0 0x1b 0x2>,
+ <0x0 0x12 0x0>;
+ interrupt-names = "err",
+ "rx",
+ "tx",
+ "batt-present";
+ qcom,sample-rate = <8>;
+ qcom,min-clock-period = <15830>;
+ qcom,max-clock-period = <122080>;
+ qcom,channel-num = <0x31>;
+ qcom,pullup-ohms = <100000>;
+ qcom,vref-microvolts = <1800000>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/coresight/coresight.txt b/Documentation/devicetree/bindings/coresight/coresight.txt
index 48f25de..c830bc4 100644
--- a/Documentation/devicetree/bindings/coresight/coresight.txt
+++ b/Documentation/devicetree/bindings/coresight/coresight.txt
@@ -10,9 +10,68 @@
Required properties:
-- compatible : name of the component used for driver matching
+- compatible : name of the component used for driver matching, should be one of
+ the following:
+ "arm,coresight-tmc" for coresight tmc-etr or tmc-etf device,
+ "arm,coresight-tpiu" for coresight tpiu device,
+ "qcom,coresight-replicator" for coresight replicator device,
+ "arm,coresight-funnel" for coresight funnel devices,
+ "arm,coresight-stm" for coresight stm trace device,
+ "arm,coresight-etm" for coresight etm trace devices,
+ "qcom,coresight-csr" for coresight csr device,
+ "arm,coresight-cti" for coresight cti devices
- reg : physical base address and length of the register set(s) of the component
-- reg-names: names corresponding to each reg property value
+- reg-names : names corresponding to each reg property value. The reg-names that
+ need to be used with corresponding compatible string for a coresight device
+ are:
+ - for coresight tmc-etr device:
+ compatible : should be "arm,coresight-tmc"
+ reg-names : should be:
+ "tmc-etr-base" - physical base address of tmc-etr registers
+ "tmc-etr-bam-base" - physical base address of tmc-etr bam
+ registers
+ - for coresight tmc-etf device:
+ compatible : should be "arm,coresight-tmc"
+ reg-names : should be:
+ "tmc-etf-base" - physical base address of tmc-etf registers
+ - for coresight tpiu device:
+ compatible : should be "arm,coresight-tpiu"
+ reg-names : should be:
+ "tpiu-base" - physical base address of tpiu registers
+ - for coresight replicator device
+ compatible : should be "qcom,coresight-replicator"
+ reg-names : should be:
+ "replicator-base" - physical base address of replicator registers
+ - for coresight funnel devices
+ compatible : should be "arm,coresight-funnel"
+ reg-names : should be:
+ "funnel-<val>-base" - physical base address of funnel registers
+ where <val> can be "merg", "in0", "in1", "kpss", "a7ss" or
+ "mmss"
+ - for coresight stm trace device
+ compatible : should be "arm,coresight-stm"
+ reg-names : should be:
+ "stm-base" - physical base address of stm registers
+ "stm-data-base" - physical base address of stm data registers
+ - for coresight etm trace devices
+ compatible : should be "arm,coresight-etm"
+ reg-names : should be:
+ "etm<num>-base" - physical base address of etm registers in
+ general where <num> is the number of etm components or cores
+ present for more than one cpu core
+ - for coresight csr device:
+ compatible : should be "qcom,coresight-csr"
+ reg-names : should be:
+ "csr-base" - physical base address of csr registers
+ - for coresight cti devices:
+ compatible : should be "arm,coresight-cti"
+ reg-names : should be:
+ "cti<num>-base" - physical base address of cti registers in general
+ where <num> is the cti component number for more than one
+ cti components
+ "cti-cpu<num>-base" - physical base address of cti cpu registers
+ where <num> is the component number for more than one cpu core
+ "cti-l2" - physical base address of L2 cti registers
- coresight-id : unique integer identifier for the component
- coresight-name : unique descriptive name of the component
- coresight-nr-inports : number of input ports on the component
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index 0f31a38..17b878c 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -43,6 +43,11 @@
previous property, the amount of fetch ids
defined should match the number of offsets
defined in property: qcom,mdss-pipe-dma-off
+- qcom,mdss-smp-data: Array of shared memory pool data. There should
+ be only two values in this property. The first
+ value corresponds to the number of smp blocks
+ and the second is the size of each block
+ present in the mdss hardware.
- qcom,mdss-ctl-off: Array of offset addresses for the available ctl
hw blocks within MDP, these offsets are
calculated from register "mdp_phys" defined in
@@ -123,6 +128,7 @@
qcom,mdss-pipe-vig-fetch-id = <1 4 7>;
qcom,mdss-pipe-rgb-fetch-id = <16 17 18>;
qcom,mdss-pipe-dma-fetch-id = <10 13>;
+ qcom,mdss-smp-data = <22 4096>;
qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800
0x00000900 0x0000A00>;
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
index bb66e7b..8de8bdd 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
@@ -30,7 +30,16 @@
2 : 2K
3 : 4K
- qcom,pre-div-channel-scaling : Pre-div used for the channel before the signal
- is being measured.
+ is being measured. Some of the AMUX channels
+ support dividing the signal from a predetermined
+ ratio. The configuration for this node is to know
+ the pre-determined ratio and use it for post scaling.
+ Select from the following unsinged int.
+ 0 : {1, 1}
+ 1 : {1, 3}
+ 2 : {1, 4}
+ 3 : {1, 6}
+ 4 : {1, 20}
- qcom,calibration-type : Reference voltage to use for channel calibration.
Channel calibration is dependendent on the channel.
Certain channels like XO_THERM, BATT_THERM use ratiometric
@@ -96,10 +105,39 @@
label = "usb_in";
reg = <0>;
qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <20>;
+ qcom,pre-div-channel-scaling = <4>;
qcom,calibration-type = "absolute";
qcom,scale-function = <0>;
qcom,hw-settle-time = <0>;
qcom,fast-avg-setup = <0>;
};
};
+
+/* Clients have an option of measuring an analog signal through an MPP.
+ MPP block is not part of the VADC block but is an individual PMIC
+ block that has an option to support clients to configure an MPP as
+ an analog input which can be routed through one of the VADC pre-mux
+ inputs. Here is an example of how to configure an MPP as an analog
+ input */
+
+/* Configure MPP4 as an Analog input to AMUX8 and read from channel 0x23 */
+/* MPP DT configuration in the platform DT file*/
+ mpp@a300 { /* MPP 4 */
+ qcom,mode = <4>; /* AIN input */
+ qcom,invert = <1>; /* Enable MPP */
+ qcom,ain-route = <3>; /* AMUX 8 */
+ qcom,master-en = <1>;
+ qcom,src-sel = <0>; /* Function constant */
+ };
+
+/* VADC Channel configuration */
+ chan@23 {
+ label = "mpp4_div3";
+ reg = <0x23>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
diff --git a/Documentation/devicetree/bindings/i2c/i2c-qup.txt b/Documentation/devicetree/bindings/i2c/i2c-qup.txt
index 60de396..a7976e8 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-qup.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-qup.txt
@@ -24,6 +24,11 @@
desired I2C bus frequency. If this value is not
provided, the source clock is assumed to be running
at 19.2 MHz.
+ - qcom,scl-gpio : I2C clock GPIO number. Required for execution of bus
+ recovery procedure.
+ - qcom,sda-gpio : I2C data GPIO number. Required for execution of bus
+ recovery procedure.
+
Example:
i2c@f9966000 {
cell-index = <0>;
@@ -34,4 +39,6 @@
interrupt-names = "qup_err_intr";
qcom,i2c-bus-freq = <100000>;
qcom,i2c-src-freq = <24000000>;
+ qcom,scl-gpio = <&msmgpio 7 0>;
+ qcom,sda-gpio = <&msmgpio 6 0>;
};
diff --git a/Documentation/devicetree/bindings/media/video/msm-cpp.txt b/Documentation/devicetree/bindings/media/video/msm-cpp.txt
index 9d176d8..c345d38 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cpp.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cpp.txt
@@ -7,8 +7,9 @@
- reg : offset and length of the register set for the device
for the cpp operating in compatible mode.
- reg-names : should specify relevant names to each reg property defined.
- - cpp - has CPP hardware register set.
+ - cpp - has CPP MICRO register set.
- cpp_vbif - has VBIF core register set used by CPP.
+ - cpp_hw - has CPP hardware register set.
- interrupts : should contain the cpp interrupt.
- interrupt-names : should specify relevant names to each interrupts
property defined.
@@ -21,7 +22,8 @@
compatible = "qcom,cpp";
reg = <0xfda04000 0x100>;
<0xfda40000 0x200>;
- reg-names = "cpp", "cpp_vbif";
+ <0xfd180000 0x008>;
+ reg-names = "cpp", "cpp_vbif", "cpp_hw";
interrupts = <0 49 0>;
interrupt-names = "cpp";
vdd-supply = <&gdsc_vfe>;
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index 6aa4ee7..24b6b36 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -44,10 +44,18 @@
- gpios - specifies gpios assigned for sdhc slot.
- qcom,gpio-names - a list of strings that map in order to the list of gpios
+ A slot has either gpios or dedicated tlmm pins as represented below.
+ - qcom,pad-pull-on - Active pull configuration for sdc tlmm pins
+ - qcom,pad-pull-off - Suspend pull configuration for sdc tlmm pins.
+ - qcom,pad-drv-on - Active drive strength configuration for sdc tlmm pins.
+ - qcom,pad-drv-off - Suspend drive strength configuration for sdc tlmm pins.
+ Tlmm pins are specified as <clk cmd data>
+
Example:
aliases {
sdhc1 = &sdhc_1;
+ sdhc2 = &sdhc_2;
};
sdhc_1: qcom,sdhc@f9824900 {
@@ -79,3 +87,21 @@
<&msmgpio 35 0>; /* DATA3 */
qcom,gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
};
+
+ sdhc_2: qcom,sdhc@f98a4900 {
+ 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";
+
+ vdd-supply = <&pm8941_l21>;
+ vdd-io-supply = <&pm8941_l13>;
+
+ qcom,bus-width = <4>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+ };
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index a868b75..4590227 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -54,7 +54,7 @@
each should be their own subnode.
Sub node required properties:
-- compatible: Must be "qcom,charger".
+- compatible: Must be "qcom,qpnp-charger".
- reg: Specifies the SPMI address and size for this peripheral.
- interrupts: Specifies the interrupt associated with the peripheral.
- interrupt-names: Specifies the interrupt names for the peripheral. Every
@@ -125,7 +125,7 @@
Example:
pm8941-chg {
spmi-dev-container;
- compatible = "qcom,charger";
+ compatible = "qcom,qpnp-charger";
#address-cells = <1>;
#size-cells = <1>;
diff --git a/Documentation/devicetree/bindings/regulator/krait-regulator.txt b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
index c783ac8..aaa731e 100644
--- a/Documentation/devicetree/bindings/regulator/krait-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
@@ -9,6 +9,10 @@
[First Level Nodes]
Required properties:
- compatible: Must be "qcom,krait-pdn"
+- reg: Specifies the physical address of the APCS GCC
+ register base
+- reg-names: "apcs_gcc" -string to identify the area where
+ the APCS GCC registers reside.
Optional properties:
- qcom,use-phase-switching indicates whether the driver should add/shed phases on the PMIC
@@ -42,7 +46,9 @@
binding, defined in regulator.txt, can also be used.
Example:
- krait_pdn: krait-pdn {
+ krait_pdn: krait-pdn@f9011000 {
+ reg = <0xf9011000 0x1000>;
+ reg-names = "apcs_gcc";
compatible = "qcom,krait-pdn";
qcom,use-phase-switching;
#address-cells = <1>;
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index fed8cb4..4cd9f99 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -434,6 +434,7 @@
- prim-auxpcm-gpio-sync : GPIO on which AUXPCM SYNC signal is coming.
- prim-auxpcm-gpio-din : GPIO on which AUXPCM DIN signal is coming.
- prim-auxpcm-gpio-dout : GPIO on which AUXPCM DOUT signal is coming.
+- qcom,us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
Optional properties:
- qcom,hdmi-audio-rx: specifies if HDMI audio support is enabled or not.
@@ -476,6 +477,7 @@
qcom,cdc-mclk-gpios = <&pm8941_gpios 15 0>;
taiko-mclk-clk = <&pm8941_clkdiv1>;
qcom,taiko-mclk-clk-freq = <9600000>;
+ qcom,us-euro-gpios = <&pm8941_gpios 20 0>;
qcom,hdmi-audio-rx;
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 2cdc7ff..a1510f3 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -52,6 +52,8 @@
- qcom,hsusb-otg-clk-always-on-workaround: If present then USB core clocks
remain active upon receiving bus suspend and USB cable is connected.
Used for allowing USB to respond for remote wakup.
+- qcom,hsusb-otg-delay-lpm: If present then USB core will wait one second
+ after disconnect before entering low power mode.
- <supply-name>-supply: handle to the regulator device tree node
Required "supply-name" is "HSUSB_VDDCX" (when voting for VDDCX) or
"hsusb_vdd_dig" (when voting for VDDCX Corner voltage),
@@ -107,6 +109,8 @@
Optional properties :
- 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
Example MSM HSUSB EHCI controller device node :
ehci: qcom,ehci-host@f9a55000 {
diff --git a/Documentation/hid/uhid.txt b/Documentation/hid/uhid.txt
new file mode 100644
index 0000000..4627c42
--- /dev/null
+++ b/Documentation/hid/uhid.txt
@@ -0,0 +1,169 @@
+ UHID - User-space I/O driver support for HID subsystem
+ ========================================================
+
+The HID subsystem needs two kinds of drivers. In this document we call them:
+
+ 1. The "HID I/O Driver" is the driver that performs raw data I/O to the
+ low-level device. Internally, they register an hid_ll_driver structure with
+ the HID core. They perform device setup, read raw data from the device and
+ push it into the HID subsystem and they provide a callback so the HID
+ subsystem can send data to the device.
+
+ 2. The "HID Device Driver" is the driver that parses HID reports and reacts on
+ them. There are generic drivers like "generic-usb" and "generic-bluetooth"
+ which adhere to the HID specification and provide the standardizes features.
+ But there may be special drivers and quirks for each non-standard device out
+ there. Internally, they use the hid_driver structure.
+
+Historically, the USB stack was the first subsystem to provide an HID I/O
+Driver. However, other standards like Bluetooth have adopted the HID specs and
+may provide HID I/O Drivers, too. The UHID driver allows to implement HID I/O
+Drivers in user-space and feed the data into the kernel HID-subsystem.
+
+This allows user-space to operate on the same level as USB-HID, Bluetooth-HID
+and similar. It does not provide a way to write HID Device Drivers, though. Use
+hidraw for this purpose.
+
+There is an example user-space application in ./samples/uhid/uhid-example.c
+
+The UHID API
+------------
+
+UHID is accessed through a character misc-device. The minor-number is allocated
+dynamically so you need to rely on udev (or similar) to create the device node.
+This is /dev/uhid by default.
+
+If a new device is detected by your HID I/O Driver and you want to register this
+device with the HID subsystem, then you need to open /dev/uhid once for each
+device you want to register. All further communication is done by read()'ing or
+write()'ing "struct uhid_event" objects. Non-blocking operations are supported
+by setting O_NONBLOCK.
+
+struct uhid_event {
+ __u32 type;
+ union {
+ struct uhid_create_req create;
+ struct uhid_data_req data;
+ ...
+ } u;
+};
+
+The "type" field contains the ID of the event. Depending on the ID different
+payloads are sent. You must not split a single event across multiple read()'s or
+multiple write()'s. A single event must always be sent as a whole. Furthermore,
+only a single event can be sent per read() or write(). Pending data is ignored.
+If you want to handle multiple events in a single syscall, then use vectored
+I/O with readv()/writev().
+
+The first thing you should do is sending an UHID_CREATE event. This will
+register the device. UHID will respond with an UHID_START event. You can now
+start sending data to and reading data from UHID. However, unless UHID sends the
+UHID_OPEN event, the internally attached HID Device Driver has no user attached.
+That is, you might put your device asleep unless you receive the UHID_OPEN
+event. If you receive the UHID_OPEN event, you should start I/O. If the last
+user closes the HID device, you will receive an UHID_CLOSE event. This may be
+followed by an UHID_OPEN event again and so on. There is no need to perform
+reference-counting in user-space. That is, you will never receive multiple
+UHID_OPEN events without an UHID_CLOSE event. The HID subsystem performs
+ref-counting for you.
+You may decide to ignore UHID_OPEN/UHID_CLOSE, though. I/O is allowed even
+though the device may have no users.
+
+If you want to send data to the HID subsystem, you send an HID_INPUT event with
+your raw data payload. If the kernel wants to send data to the device, you will
+read an UHID_OUTPUT or UHID_OUTPUT_EV event.
+
+If your device disconnects, you should send an UHID_DESTROY event. This will
+unregister the device. You can now send UHID_CREATE again to register a new
+device.
+If you close() the fd, the device is automatically unregistered and destroyed
+internally.
+
+write()
+-------
+write() allows you to modify the state of the device and feed input data into
+the kernel. The following types are supported: UHID_CREATE, UHID_DESTROY and
+UHID_INPUT. The kernel will parse the event immediately and if the event ID is
+not supported, it will return -EOPNOTSUPP. If the payload is invalid, then
+-EINVAL is returned, otherwise, the amount of data that was read is returned and
+the request was handled successfully.
+
+ UHID_CREATE:
+ This creates the internal HID device. No I/O is possible until you send this
+ event to the kernel. The payload is of type struct uhid_create_req and
+ contains information about your device. You can start I/O now.
+
+ UHID_DESTROY:
+ This destroys the internal HID device. No further I/O will be accepted. There
+ may still be pending messages that you can receive with read() but no further
+ UHID_INPUT events can be sent to the kernel.
+ You can create a new device by sending UHID_CREATE again. There is no need to
+ reopen the character device.
+
+ UHID_INPUT:
+ You must send UHID_CREATE before sending input to the kernel! This event
+ contains a data-payload. This is the raw data that you read from your device.
+ The kernel will parse the HID reports and react on it.
+
+ UHID_FEATURE_ANSWER:
+ If you receive a UHID_FEATURE request you must answer with this request. You
+ must copy the "id" field from the request into the answer. Set the "err" field
+ to 0 if no error occured or to EIO if an I/O error occurred.
+ If "err" is 0 then you should fill the buffer of the answer with the results
+ of the feature request and set "size" correspondingly.
+
+read()
+------
+read() will return a queued ouput report. These output reports can be of type
+UHID_START, UHID_STOP, UHID_OPEN, UHID_CLOSE, UHID_OUTPUT or UHID_OUTPUT_EV. No
+reaction is required to any of them but you should handle them according to your
+needs. Only UHID_OUTPUT and UHID_OUTPUT_EV have payloads.
+
+ UHID_START:
+ This is sent when the HID device is started. Consider this as an answer to
+ UHID_CREATE. This is always the first event that is sent.
+
+ UHID_STOP:
+ This is sent when the HID device is stopped. Consider this as an answer to
+ UHID_DESTROY.
+ If the kernel HID device driver closes the device manually (that is, you
+ didn't send UHID_DESTROY) then you should consider this device closed and send
+ an UHID_DESTROY event. You may want to reregister your device, though. This is
+ always the last message that is sent to you unless you reopen the device with
+ UHID_CREATE.
+
+ UHID_OPEN:
+ This is sent when the HID device is opened. That is, the data that the HID
+ device provides is read by some other process. You may ignore this event but
+ it is useful for power-management. As long as you haven't received this event
+ there is actually no other process that reads your data so there is no need to
+ send UHID_INPUT events to the kernel.
+
+ UHID_CLOSE:
+ This is sent when there are no more processes which read the HID data. It is
+ the counterpart of UHID_OPEN and you may as well ignore this event.
+
+ UHID_OUTPUT:
+ This is sent if the HID device driver wants to send raw data to the I/O
+ device. You should read the payload and forward it to the device. The payload
+ is of type "struct uhid_data_req".
+ This may be received even though you haven't received UHID_OPEN, yet.
+
+ UHID_OUTPUT_EV:
+ Same as UHID_OUTPUT but this contains a "struct input_event" as payload. This
+ is called for force-feedback, LED or similar events which are received through
+ an input device by the HID subsystem. You should convert this into raw reports
+ and send them to your device similar to events of type UHID_OUTPUT.
+
+ UHID_FEATURE:
+ This event is sent if the kernel driver wants to perform a feature request as
+ described in the HID specs. The report-type and report-number are available in
+ the payload.
+ The kernel serializes feature requests so there will never be two in parallel.
+ However, if you fail to respond with a UHID_FEATURE_ANSWER in a time-span of 5
+ seconds, then the requests will be dropped and a new one might be sent.
+ Therefore, the payload also contains an "id" field that identifies every
+ request.
+
+Document by:
+ David Herrmann <dh.herrmann@googlemail.com>
diff --git a/MAINTAINERS b/MAINTAINERS
index b362709..5f8ab49 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6855,6 +6855,13 @@
F: Documentation/filesystems/ufs.txt
F: fs/ufs/
+UHID USERSPACE HID IO DRIVER:
+M: David Herrmann <dh.herrmann@googlemail.com>
+L: linux-input@vger.kernel.org
+S: Maintained
+F: drivers/hid/uhid.c
+F: include/linux/uhid.h
+
ULTRA-WIDEBAND (UWB) SUBSYSTEM:
L: linux-usb@vger.kernel.org
S: Orphan
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 2f686fa..4678337 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1885,18 +1885,9 @@
config ENABLE_DMM
def_bool n
-config FIX_MOVABLE_ZONE
- def_bool n
-
config DONT_MAP_HOLE_AFTER_MEMBANK0
def_bool n
-config ARCH_ENABLE_MEMORY_HOTPLUG
- def_bool n
-
-config ARCH_ENABLE_MEMORY_HOTREMOVE
- def_bool n
-
config HOLES_IN_ZONE
def_bool n
depends on SPARSEMEM
diff --git a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
index 1c3cf29..42f6033 100644
--- a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
@@ -25,7 +25,7 @@
qcom,mdss-pan-porch-values = <32 12 144 3 4 9>;
qcom,mdss-pan-underflow-clr = <0xff>;
qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
- qcom,mdss-pan-bl-levels = <1 255>;
+ qcom,mdss-pan-bl-levels = <1 4095>;
qcom,mdss-pan-dsi-mode = <0>;
qcom,mdss-pan-dsi-h-pulse-mode = <0>;
qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 6a07bad..44ece9e 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -49,6 +49,109 @@
};
};
+ pm8226_chg: qcom,charger {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-charger";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+
+ 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-chgr@1000 {
+ status = "disabled";
+ reg = <0x1000 0x100>;
+ interrupts = <0x0 0x10 0x0>,
+ <0x0 0x10 0x1>,
+ <0x0 0x10 0x2>,
+ <0x0 0x10 0x3>,
+ <0x0 0x10 0x4>,
+ <0x0 0x10 0x5>,
+ <0x0 0x10 0x6>,
+ <0x0 0x10 0x7>;
+
+ interrupt-names = "vbat-det-lo",
+ "vbat-det-hi",
+ "chgwdog",
+ "state-change",
+ "trkl-chg-on",
+ "fast-chg-on",
+ "chg-failed",
+ "chg-done";
+ };
+
+ qcom,chg-buck@1100 {
+ status = "disabled";
+ reg = <0x1100 0x100>;
+ interrupts = <0x0 0x11 0x0>,
+ <0x0 0x11 0x1>,
+ <0x0 0x11 0x2>,
+ <0x0 0x11 0x3>,
+ <0x0 0x11 0x4>,
+ <0x0 0x11 0x5>,
+ <0x0 0x11 0x6>;
+
+ interrupt-names = "vbat-ov",
+ "vreg-ov",
+ "overtemp",
+ "vchg-loop",
+ "ichg-loop",
+ "ibat-loop",
+ "vdd-loop";
+ };
+
+ qcom,chg-bat-if@1200 {
+ status = "disabled";
+ reg = <0x1200 0x100>;
+ interrupts = <0x0 0x12 0x0>,
+ <0x0 0x12 0x1>,
+ <0x0 0x12 0x2>,
+ <0x0 0x12 0x3>,
+ <0x0 0x12 0x4>;
+
+ interrupt-names = "batt-pres",
+ "bat-temp-ok",
+ "bat-fet-on",
+ "vcp-on",
+ "psi";
+
+ };
+
+ qcom,chg-usb-chgpth@1300 {
+ status = "disabled";
+ reg = <0x1300 0x100>;
+ interrupts = <0 0x13 0x0>,
+ <0 0x13 0x1>,
+ <0x0 0x13 0x2>;
+
+ interrupt-names = "coarse-det-usb",
+ "usbin-valid",
+ "chg-gone";
+ };
+
+ qcom,chg-boost@1500 {
+ status = "disabled";
+ reg = <0x1500 0x100>;
+ interrupts = <0x0 0x15 0x0>,
+ <0x0 0x15 0x1>;
+
+ interrupt-names = "boost-pwr-ok",
+ "limit-error";
+ };
+
+ qcom,chg-misc@1600 {
+ status = "disabled";
+ reg = <0x1600 0x100>;
+ };
+ };
+
pm8226_gpios: gpios {
spmi-dev-container;
compatible = "qcom,qpnp-pin";
@@ -498,6 +601,12 @@
status = "disabled";
};
+ qcom,leds@d800 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xd800 0x100>;
+ label = "wled";
+ };
+
regulator@8000 {
regulator-name = "8226_lvs1";
reg = <0x8000 0x100>;
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 54f603d..892afbb 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -58,6 +58,28 @@
};
};
+ bif_ctrl: qcom,bsi@1b00 {
+ compatible = "qcom,qpnp-bsi";
+ reg = <0x1b00 0x100>,
+ <0x1208 0x1>;
+ reg-names = "bsi-base", "batt-id-status";
+ label = "pm8941-bsi";
+ interrupts = <0x0 0x1b 0x0>,
+ <0x0 0x1b 0x1>,
+ <0x0 0x1b 0x2>,
+ <0x0 0x12 0x0>;
+ interrupt-names = "err",
+ "rx",
+ "tx",
+ "batt-present";
+ qcom,channel-num = <0x31>;
+ qcom,pullup-ohms = <100000>;
+ qcom,vref-microvolts = <1800000>;
+ qcom,min-clock-period = <1000>;
+ qcom,max-clock-period = <160000>;
+ qcom,sample-rate = <4>;
+ };
+
pm8941_bms: qcom,bms {
spmi-dev-container;
compatible = "qcom,qpnp-bms";
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
index f01491f..a2707ee 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -85,3 +85,79 @@
status = "ok";
};
+
+&spmi_bus {
+ qcom,pm8226@1 {
+ qcom,leds@d800 {
+ status = "okay";
+ qcom,wled_0 {
+ label = "wled";
+ linux,name = "wled:backlight";
+ linux,default-trigger = "bkl-trigger";
+ qcom,cs-out-en;
+ qcom,op-fdbck;
+ qcom,default-state = "on";
+ qcom,max-current = <25>;
+ qcom,ctrl-delay-us = <0>;
+ qcom,boost-curr-lim = <3>;
+ qcom,cp-sel = <0>;
+ qcom,switch-freq = <2>;
+ qcom,ovp-val = <2>;
+ qcom,num-strings = <1>;
+ qcom,id = <0>;
+ };
+ };
+ };
+};
+
+&pm8226_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+
+ gpio@c600 { /* GPIO 7 */
+ };
+
+ gpio@c700 { /* GPIO 8 */
+ };
+};
+
+&pm8226_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ };
+
+ mpp@a600 { /* MPP 7 */
+ };
+
+ mpp@a700 { /* MPP 8 */
+ };
+};
diff --git a/arch/arm/boot/dts/msm8226-coresight.dtsi b/arch/arm/boot/dts/msm8226-coresight.dtsi
new file mode 100644
index 0000000..8d5d23c
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-coresight.dtsi
@@ -0,0 +1,156 @@
+/* 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.
+ */
+
+/ {
+ tmc_etr: tmc@fc322000 {
+ compatible = "arm,coresight-tmc";
+ reg = <0xfc322000 0x1000>,
+ <0xfc37c000 0x3000>;
+ reg-names = "tmc-etr-base", "tmc-etr-bam-base";
+
+ qcom,memory-reservation-type = "EBI1";
+ qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
+
+ coresight-id = <0>;
+ coresight-name = "coresight-tmc-etr";
+ coresight-nr-inports = <1>;
+ };
+
+ tpiu: tpiu@fc318000 {
+ compatible = "arm,coresight-tpiu";
+ reg = <0xfc318000 0x1000>;
+ reg-names = "tpiu-base";
+
+ coresight-id = <1>;
+ coresight-name = "coresight-tpiu";
+ coresight-nr-inports = <1>;
+ };
+
+ replicator: replicator@fc31c000 {
+ compatible = "qcom,coresight-replicator";
+ reg = <0xfc31c000 0x1000>;
+ reg-names = "replicator-base";
+
+ coresight-id = <2>;
+ coresight-name = "coresight-replicator";
+ coresight-nr-inports = <1>;
+ coresight-outports = <0 1>;
+ coresight-child-list = <&tmc_etr &tpiu>;
+ coresight-child-ports = <0 0>;
+ };
+
+ tmc_etf: tmc@fc307000 {
+ compatible = "arm,coresight-tmc";
+ reg = <0xfc307000 0x1000>;
+ reg-names = "tmc-etf-base";
+
+ coresight-id = <3>;
+ coresight-name = "coresight-tmc-etf";
+ coresight-nr-inports = <1>;
+ coresight-outports = <0>;
+ coresight-child-list = <&replicator>;
+ coresight-child-ports = <0>;
+ coresight-default-sink;
+ };
+
+ funnel_merg: funnel@fc31b000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc31b000 0x1000>;
+ reg-names = "funnel-merg-base";
+
+ coresight-id = <4>;
+ coresight-name = "coresight-funnel-merg";
+ coresight-nr-inports = <2>;
+ coresight-outports = <0>;
+ coresight-child-list = <&tmc_etf>;
+ coresight-child-ports = <0>;
+ };
+
+ funnel_in0: funnel@fc319000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc319000 0x1000>;
+ reg-names = "funnel-in0-base";
+
+ coresight-id = <5>;
+ coresight-name = "coresight-funnel-in0";
+ coresight-nr-inports = <8>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_merg>;
+ coresight-child-ports = <0>;
+ };
+
+ funnel_in1: funnel@fc31a000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc31a000 0x1000>;
+ reg-names = "funnel-in1-base";
+
+ coresight-id = <6>;
+ coresight-name = "coresight-funnel-in1";
+ coresight-nr-inports = <8>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_merg>;
+ coresight-child-ports = <1>;
+ };
+
+ funnel_a7ss: funnel@fc345000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc345000 0x1000>;
+ reg-names = "funnel-a7ss-base";
+
+ coresight-id = <7>;
+ coresight-name = "coresight-funnel-a7ss";
+ coresight-nr-inports = <4>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in1>;
+ coresight-child-ports = <5>;
+ };
+
+ funnel_mmss: funnel@fc364000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc364000 0x1000>;
+ reg-names = "funnel-mmss-base";
+
+
+ coresight-id = <8>;
+ coresight-name = "coresight-funnel-mmss";
+ coresight-nr-inports = <8>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in1>;
+ coresight-child-ports = <1>;
+ };
+
+ stm: stm@fc321000 {
+ compatible = "arm,coresight-stm";
+ reg = <0xfc321000 0x1000>,
+ <0xfa280000 0x180000>;
+ reg-names = "stm-base", "stm-data-base";
+
+ coresight-id = <9>;
+ coresight-name = "coresight-stm";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in1>;
+ coresight-child-ports = <7>;
+ };
+
+ csr: csr@fc302000 {
+ compatible = "qcom,coresight-csr";
+ reg = <0xfc302000 0x1000>;
+ reg-names = "csr-base";
+
+ coresight-id = <10>;
+ coresight-name = "coresight-csr";
+ coresight-nr-inports = <0>;
+
+ qcom,blk-size = <3>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
new file mode 100644
index 0000000..1691743
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -0,0 +1,62 @@
+/* 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_mdp@fd900000 {
+ compatible = "qcom,mdss_mdp";
+ reg = <0xfd900000 0x22100>,
+ <0xfd924000 0x1000>;
+ reg-names = "mdp_phys", "vbif_phys";
+ interrupts = <0 72 0>;
+ vdd-supply = <&gdsc_mdss>;
+
+ qcom,mdss-pipe-vig-off = <0x00001200>;
+ qcom,mdss-pipe-rgb-off = <0x00001E00>;
+ qcom,mdss-pipe-dma-off = <0x00002A00>;
+ qcom,mdss-pipe-vig-fetch-id = <1>;
+ qcom,mdss-pipe-rgb-fetch-id = <7>;
+ qcom,mdss-pipe-dma-fetch-id = <4>;
+ qcom,mdss-smp-data = <7 4096>;
+
+ qcom,mdss-ctl-off = <0x00000600 0x00000700>;
+ qcom,mdss-mixer-intf-off = <0x00003200>;
+ qcom,mdss-mixer-wb-off = <0x00003E00>;
+ qcom,mdss-dspp-off = <0x00004600>;
+ qcom,mdss-wb-off = <0x00011100 0x00013100>;
+ qcom,mdss-intf-off = <0x00000000 0x00021300>;
+
+ qcom,vbif-settings = <0x004 0x00000001>,
+ <0x0D8 0x00000707>,
+ <0x124 0x00000003>;
+ qcom,mdp-settings = <0x02E0 0x000000A9>,
+ <0x02E4 0x00000055>;
+
+ mdss_fb0: qcom,mdss_fb_primary {
+ cell-index = <0>;
+ compatible = "qcom,mdss-fb";
+ qcom,memory-reservation-type = "EBI1";
+ qcom,memory-reservation-size = <0x800000>;
+ };
+
+ mdss_fb1: qcom,mdss_fb_wfd {
+ cell-index = <1>;
+ compatible = "qcom,mdss-fb";
+ };
+ };
+
+ qcom,mdss_wb_panel {
+ compatible = "qcom,mdss_wb";
+ qcom,mdss_pan_res = <1280 720>;
+ qcom,mdss_pan_bpp = <24>;
+ qcom,mdss-fb-map = <&mdss_fb1>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8226-mtp.dts b/arch/arm/boot/dts/msm8226-mtp.dts
index 0242540..43f6685 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-mtp.dts
@@ -82,3 +82,79 @@
status = "ok";
};
+
+&spmi_bus {
+ qcom,pm8226@1 {
+ qcom,leds@d800 {
+ status = "okay";
+ qcom,wled_0 {
+ label = "wled";
+ linux,name = "wled:backlight";
+ linux,default-trigger = "bkl-trigger";
+ qcom,cs-out-en;
+ qcom,op-fdbck;
+ qcom,default-state = "on";
+ qcom,max-current = <25>;
+ qcom,ctrl-delay-us = <0>;
+ qcom,boost-curr-lim = <3>;
+ qcom,cp-sel = <0>;
+ qcom,switch-freq = <2>;
+ qcom,ovp-val = <2>;
+ qcom,num-strings = <1>;
+ qcom,id = <0>;
+ };
+ };
+ };
+};
+
+&pm8226_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+
+ gpio@c600 { /* GPIO 7 */
+ };
+
+ gpio@c700 { /* GPIO 8 */
+ };
+};
+
+&pm8226_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ };
+
+ mpp@a600 { /* MPP 7 */
+ };
+
+ mpp@a700 { /* MPP 8 */
+ };
+};
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
index 4937efe..6348f5a 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -309,10 +309,12 @@
qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
<53 104>, /* mdss_irq */
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+ <0xff 56>, /* q6_wdog_expired_irq */
<0xff 57>, /* mss_to_apps_irq(0) */
<0xff 58>, /* mss_to_apps_irq(1) */
<0xff 59>, /* mss_to_apps_irq(2) */
<0xff 60>, /* mss_to_apps_irq(3) */
+ <0xff 61>, /* mss_a2_bam_irq */
<0xff 173>, /* o_wcss_apss_smd_hi */
<0xff 174>, /* o_wcss_apss_smd_med */
<0xff 175>, /* o_wcss_apss_smd_low */
@@ -320,17 +322,15 @@
<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
<0xff 179>, /* o_wcss_apss_asic_intr
-
+ <0xff 181>, /* o_wcss_apss_wdog_bite_and_reset_rdy */
<0xff 188>, /* lpass_irq_out_apcs(0) */
<0xff 189>, /* lpass_irq_out_apcs(1) */
<0xff 190>, /* lpass_irq_out_apcs(2) */
<0xff 191>, /* lpass_irq_out_apcs(3) */
<0xff 192>, /* lpass_irq_out_apcs(4) */
- <0xff 193>, /* lpass_irq_out_apcs(5) */
- <0xff 194>, /* lpass_irq_out_apcs(6) */
- <0xff 195>, /* lpass_irq_out_apcs(7) */
- <0xff 196>, /* lpass_irq_out_apcs(8) */
- <0xff 197>, /* lpass_irq_out_apcs(9) */
+ <0xff 194>, /* lpass_irq_out_apcs[6] */
+ <0xff 195>, /* lpass_irq_out_apcs[7] */
+ <0xff 196>, /* lpass_irq_out_apcs[8] */
<0xff 200>, /* rpm_ipc(4) */
<0xff 201>, /* rpm_ipc(5) */
<0xff 202>, /* rpm_ipc(6) */
@@ -339,47 +339,54 @@
<0xff 205>, /* rpm_ipc(25) */
<0xff 206>, /* rpm_ipc(26) */
<0xff 207>, /* rpm_ipc(27) */
+ <0xff 258>, /* rpm_ipc(28) */
+ <0xff 259>, /* rpm_ipc(29) */
+ <0xff 275>, /* rpm_ipc(30) */
+ <0xff 276>, /* rpm_ipc(31) */
+ <0xff 269>, /* rpm_wdog_expired_irq */
<0xff 240>; /* summary_irq_kpss */
qcom,gpio-parent = <&msmgpio>;
- qcom,gpio-map = <3 102>,
- <4 1 >,
+ qcom,gpio-map = <3 1>,
+ <4 4 >,
<5 5 >,
<6 9 >,
- <7 18>,
- <8 20>,
- <9 24>,
+ <7 13>,
+ <8 17>,
+ <9 21>,
<10 27>,
- <11 28>,
- <12 34>,
- <13 35>,
- <14 37>,
- <15 42>,
- <16 44>,
- <17 46>,
- <18 50>,
- <19 54>,
- <20 59>,
- <21 61>,
- <22 62>,
- <23 64>,
- <24 65>,
- <25 66>,
- <26 67>,
- <27 68>,
- <28 71>,
- <29 72>,
- <30 73>,
- <31 74>,
- <32 75>,
- <33 77>,
- <34 79>,
- <35 80>,
- <36 82>,
- <37 86>,
- <38 92>,
- <39 93>,
- <40 95>;
+ <11 29>,
+ <12 31>,
+ <13 33>,
+ <14 35>,
+ <15 37>,
+ <16 38>,
+ <17 39>,
+ <18 41>,
+ <19 46>,
+ <20 48>,
+ <21 49>,
+ <22 50>,
+ <23 51>,
+ <24 52>,
+ <25 54>,
+ <26 62>,
+ <27 63>,
+ <28 64>,
+ <29 65>,
+ <30 66>,
+ <31 67>,
+ <32 68>,
+ <33 69>,
+ <34 71>,
+ <35 72>,
+ <36 106>,
+ <37 107>,
+ <38 108>,
+ <39 109>,
+ <40 110>,
+ <54 111>,
+ <55 113>;
};
qcom,pm-8x60@fe805664 {
diff --git a/arch/arm/boot/dts/msm8226-qrd.dts b/arch/arm/boot/dts/msm8226-qrd.dts
index 65d4b33..482a5da 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-qrd.dts
@@ -85,3 +85,79 @@
status = "ok";
};
+
+&spmi_bus {
+ qcom,pm8226@1 {
+ qcom,leds@d800 {
+ status = "okay";
+ qcom,wled_0 {
+ label = "wled";
+ linux,name = "wled:backlight";
+ linux,default-trigger = "bkl-trigger";
+ qcom,cs-out-en;
+ qcom,op-fdbck;
+ qcom,default-state = "on";
+ qcom,max-current = <25>;
+ qcom,ctrl-delay-us = <0>;
+ qcom,boost-curr-lim = <3>;
+ qcom,cp-sel = <0>;
+ qcom,switch-freq = <2>;
+ qcom,ovp-val = <2>;
+ qcom,num-strings = <1>;
+ qcom,id = <0>;
+ };
+ };
+ };
+};
+
+&pm8226_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+
+ gpio@c600 { /* GPIO 7 */
+ };
+
+ gpio@c700 { /* GPIO 8 */
+ };
+};
+
+&pm8226_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ };
+
+ mpp@a600 { /* MPP 7 */
+ };
+
+ mpp@a700 { /* MPP 8 */
+ };
+};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 741ffbd..8111b40 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -18,6 +18,8 @@
/include/ "msm8226-smp2p.dtsi"
/include/ "msm8226-gpu.dtsi"
/include/ "msm8226-bus.dtsi"
+/include/ "msm8226-mdss.dtsi"
+/include/ "msm8226-coresight.dtsi"
/ {
model = "Qualcomm MSM 8226";
@@ -92,7 +94,7 @@
qcom,hsusb-otg-phy-type = <2>;
qcom,hsusb-otg-mode = <1>;
- qcom,hsusb-otg-otg-control = <1>;
+ qcom,hsusb-otg-otg-control = <2>;
qcom,hsusb-otg-disable-reset;
qcom,msm-bus,name = "usb2";
@@ -346,7 +348,7 @@
qcom,smem@fa00000 {
compatible = "qcom,smem";
reg = <0xfa00000 0x200000>,
- <0xfa006000 0x1000>,
+ <0xf9011000 0x1000>,
<0xfc428000 0x4000>;
reg-names = "smem", "irq-reg-base", "aux-mem1";
@@ -592,6 +594,12 @@
reg = <0xfc834000 0x7000>;
interrupts = <0 29 1>;
};
+
+ qcom,msm-rtb {
+ compatible = "qcom,msm-rtb";
+ qcom,memory-reservation-type = "EBI1";
+ qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
+ };
};
&gdsc_venus {
@@ -709,4 +717,32 @@
qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
};
+
+};
+
+&pm8226_chg {
+ status = "ok";
+
+ qcom,chg-charging-disabled;
+ qcom,chg-use-default-batt-values;
+
+ qcom,chg-chgr@1000 {
+ status = "ok";
+ };
+
+ qcom,chg-buck@1100 {
+ status = "ok";
+ };
+
+ qcom,chg-usb-chgpth@1300 {
+ status = "ok";
+ };
+
+ qcom,chg-boost@1500 {
+ status = "ok";
+ };
+
+ qcom,chg-misc@1600 {
+ status = "ok";
+ };
};
diff --git a/arch/arm/boot/dts/msm8610-ion.dtsi b/arch/arm/boot/dts/msm8610-ion.dtsi
index 0abaca5..107961d 100644
--- a/arch/arm/boot/dts/msm8610-ion.dtsi
+++ b/arch/arm/boot/dts/msm8610-ion.dtsi
@@ -20,14 +20,6 @@
reg = <30>;
};
- qcom,ion-heap@8 { /* CP_MM HEAP */
- compatible = "qcom,msm-ion-reserve";
- reg = <8>;
- qcom,heap-align = <0x1000>;
- qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x3800000>;
- };
-
qcom,ion-heap@25 { /* IOMMU HEAP */
reg = <25>;
};
@@ -37,7 +29,7 @@
reg = <27>;
qcom,heap-align = <0x1000>;
qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x780000>;
+ qcom,memory-reservation-size = <0x100000>;
};
qcom,ion-heap@28 { /* AUDIO HEAP */
@@ -47,16 +39,6 @@
qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
qcom,memory-reservation-size = <0x314000>;
};
-
- qcom,ion-heap@29 { /* FIRMWARE HEAP */
- compatible = "qcom,msm-ion-reserve";
- reg = <29>;
- qcom,heap-align = <0x20000>;
- qcom,heap-adjacent = <8>;
- qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0xA00000>;
- };
-
};
};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index ce6011b..2dff4c7 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -166,7 +166,7 @@
qcom,smem@d600000 {
compatible = "qcom,smem";
reg = <0xd600000 0x200000>,
- <0xfa006000 0x1000>,
+ <0xf9011000 0x1000>,
<0xfc428000 0x4000>;
reg-names = "smem", "irq-reg-base", "aux-mem1";
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index ea99aa3..ebb3912 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -159,8 +159,9 @@
cell-index = <0>;
compatible = "qcom,cpp";
reg = <0xfda04000 0x100>,
- <0xfda40000 0x200>;
- reg-names = "cpp", "cpp_vbif";
+ <0xfda40000 0x200>,
+ <0xfda18000 0x008>;
+ reg-names = "cpp", "cpp_vbif", "cpp_hw";
interrupts = <0 49 0>;
interrupt-names = "cpp";
vdd-supply = <&gdsc_vfe>;
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 0acfaf6..ad26061 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -294,8 +294,49 @@
wp-gpios = <&pm8941_gpios 29 0x1>;
};
+&sdhc_1 {
+ vdd-supply = <&pm8941_l20>;
+ vdd-io-supply = <&pm8941_s3>;
+
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <800 500000>;
+
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <250 154000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,nonremovable;
+};
+
+&sdhc_2 {
+ vdd-supply = <&pm8941_l21>;
+ vdd-io-supply = <&pm8941_l13>;
+
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <9000 800000>;
+
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <6 22000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+};
+
&uart7 {
status = "ok";
+ qcom,tx-gpio = <&msmgpio 41 0x00>;
+ qcom,rx-gpio = <&msmgpio 42 0x00>;
+ qcom,cts-gpio = <&msmgpio 43 0x00>;
+ qcom,rfr-gpio = <&msmgpio 44 0x00>;
};
&usb3 {
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index 92a6e01..dbb8958 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -291,6 +291,43 @@
cd-gpios = <&msmgpio 62 0x1>;
};
+&sdhc_1 {
+ vdd-supply = <&pm8941_l20>;
+ vdd-io-supply = <&pm8941_s3>;
+
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <800 500000>;
+
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <250 154000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,nonremovable;
+};
+
+&sdhc_2 {
+ vdd-supply = <&pm8941_l21>;
+ vdd-io-supply = <&pm8941_l13>;
+
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <9000 800000>;
+
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <6 22000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+};
+
&usb3 {
qcom,otg-capability;
};
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 6e2719b..4dd92b98 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -738,3 +738,40 @@
status = "ok";
};
};
+
+&sdhc_1 {
+ vdd-supply = <&pm8941_l20>;
+ vdd-io-supply = <&pm8941_s3>;
+
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <800 500000>;
+
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <250 154000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,nonremovable;
+};
+
+&sdhc_2 {
+ vdd-supply = <&pm8941_l21>;
+ vdd-io-supply = <&pm8941_l13>;
+
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <9000 800000>;
+
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <6 22000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+};
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index 0b95419..f382c3e 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -27,6 +27,7 @@
qcom,mdss-pipe-vig-fetch-id = <1 4 7>;
qcom,mdss-pipe-rgb-fetch-id = <16 17 18>;
qcom,mdss-pipe-dma-fetch-id = <10 13>;
+ qcom,mdss-smp-data = <22 4096>;
qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800
0x00000900 0x0000A00>;
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index c6935f4..d3d53dd 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -262,6 +262,43 @@
cd-gpios = <&msmgpio 62 0x1>;
};
+&sdhc_1 {
+ vdd-supply = <&pm8941_l20>;
+ vdd-io-supply = <&pm8941_s3>;
+
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <800 500000>;
+
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <250 154000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,nonremovable;
+};
+
+&sdhc_2 {
+ vdd-supply = <&pm8941_l21>;
+ vdd-io-supply = <&pm8941_l13>;
+
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <9000 800000>;
+
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <6 22000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+};
+
&usb_otg {
qcom,hsusb-otg-otg-control = <2>;
};
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index 2dad8e7..5eff79c 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -423,7 +423,9 @@
};
/ {
- krait_pdn: krait-pdn {
+ krait_pdn: krait-pdn@f9011000 {
+ reg = <0xf9011000 0x1000>;
+ reg-names = "apcs_gcc";
compatible = "qcom,krait-pdn";
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/msm8974-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
similarity index 100%
rename from arch/arm/boot/dts/msm8974-pm.dtsi
rename to arch/arm/boot/dts/msm8974-v1-pm.dtsi
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index 64014b3..bccf0fe 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -19,6 +19,7 @@
/include/ "msm8974.dtsi"
/include/ "msm8974-v1-iommu.dtsi"
/include/ "msm8974-v1-iommu-domains.dtsi"
+/include/ "msm8974-v1-pm.dtsi"
/ {
android_usb@fc42b0c8 {
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
new file mode 100644
index 0000000..4d98a1d
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -0,0 +1,426 @@
+/* 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/ "skeleton.dtsi"
+
+/ {
+ qcom,spm@f9089000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf9089000 0x1000>;
+ qcom,core-id = <0>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-avs-ctl = <0>;
+ qcom,saw2-avs-hysteresis = <0>;
+ qcom,saw2-avs-limit = <0>;
+ qcom,saw2-avs-dly= <0>;
+ qcom,saw2-spm-dly= <0x3C102800>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
+ E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+ qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
+ E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+ };
+
+ qcom,spm@f9099000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf9099000 0x1000>;
+ qcom,core-id = <1>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-avs-ctl = <0>;
+ qcom,saw2-avs-hysteresis = <0>;
+ qcom,saw2-avs-limit = <0>;
+ qcom,saw2-avs-dly= <0>;
+ qcom,saw2-spm-dly= <0x3C102800>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
+ E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+ qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
+ E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+ };
+
+ qcom,spm@f90a9000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf90a9000 0x1000>;
+ qcom,core-id = <2>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-avs-ctl = <0>;
+ qcom,saw2-avs-hysteresis = <0>;
+ qcom,saw2-avs-limit = <0>;
+ qcom,saw2-avs-dly= <0>;
+ qcom,saw2-spm-dly= <0x3C102800>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
+ E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+ qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
+ E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+ };
+
+ qcom,spm@f90b9000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf90b9000 0x1000>;
+ qcom,core-id = <3>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-avs-ctl = <0>;
+ qcom,saw2-avs-hysteresis = <0>;
+ qcom,saw2-avs-limit = <0>;
+ qcom,saw2-avs-dly= <0>;
+ qcom,saw2-spm-dly= <0x3C102800>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
+ E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+ qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
+ E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+ };
+
+ qcom,spm@f9012000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf9012000 0x1000>;
+ qcom,core-id = <0xffff>; /* L2/APCS SAW */
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x14>;
+ qcom,saw2-avs-ctl = <0>;
+ qcom,saw2-avs-hysteresis = <0>;
+ qcom,saw2-avs-limit = <0>;
+ qcom,saw2-avs-dly= <0>;
+ qcom,saw2-spm-dly= <0x3C102800>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-pmic-data0 = <0x02030080>;
+ qcom,saw2-pmic-data1 = <0x00030000>;
+ qcom,vctl-timeout-us = <50>;
+ qcom,vctl-port = <0x0>;
+ qcom,phase-port = <0x1>;
+ qcom,pfm-port = <0x2>;
+ qcom,saw2-spm-cmd-ret = [1f 00 20 03 22 00 0f];
+ qcom,saw2-spm-cmd-gdhs = [00 20 32 60 70 80 42 07 78 80 44 22 50
+ 3b 60 02 32 50 0f];
+ qcom,saw2-spm-cmd-pc = [00 10 32 60 70 80 b0 11 42 07 01 b0 78
+ 80 12 44 50 3b 60 02 32 50 0f];
+ };
+
+ qcom,lpm-resources {
+ compatible = "qcom,lpm-resources";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,lpm-resources@0 {
+ reg = <0x0>;
+ qcom,name = "vdd-dig";
+ qcom,resource-type = <0>;
+ qcom,type = <0x62706d73>; /* "smpb" */
+ qcom,id = <0x02>;
+ qcom,key = <0x6e726f63>; /* "corn" */
+ qcom,init-value = <5>; /* Super Turbo */
+ };
+
+ qcom,lpm-resources@1 {
+ reg = <0x1>;
+ qcom,name = "vdd-mem";
+ qcom,resource-type = <0>;
+ qcom,type = <0x62706d73>; /* "smpb" */
+ qcom,id = <0x01>;
+ qcom,key = <0x7675>; /* "uv" */
+ qcom,init-value = <1050000>; /* Super Turbo */
+ };
+
+ qcom,lpm-resources@2 {
+ reg = <0x2>;
+ qcom,name = "pxo";
+ qcom,resource-type = <0>;
+ qcom,type = <0x306b6c63>; /* "clk0" */
+ qcom,id = <0x00>;
+ qcom,key = <0x62616e45>; /* "Enab" */
+ qcom,init-value = <1>; /* On */
+ };
+
+ qcom,lpm-resources@3 {
+ reg = <0x3>;
+ qcom,name = "l2";
+ qcom,resource-type = <1>;
+ qcom,init-value = <2>; /* Retention */
+ };
+ };
+
+ qcom,lpm-levels {
+ compatible = "qcom,lpm-levels";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,lpm-level@0 {
+ reg = <0x0>;
+ qcom,mode = <0>; /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <2>; /* Retention */
+ qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
+ qcom,irqs-detectable;
+ qcom.gpios-detectable;
+ qcom,latency-us = <1>;
+ qcom,ss-power = <784>;
+ qcom,energy-overhead = <190000>;
+ qcom,time-overhead = <100>;
+ };
+
+ qcom,lpm-level@1 {
+ reg = <0x1>;
+ qcom,mode = <4>; /* MSM_PM_SLEEP_MODE_RETENTION*/
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <2>; /* Retention */
+ qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
+ qcom,irqs-detectable;
+ qcom.gpios-detectable;
+ qcom,latency-us = <75>;
+ qcom,ss-power = <735>;
+ qcom,energy-overhead = <77341>;
+ qcom,time-overhead = <105>;
+ };
+
+ qcom,lpm-level@2 {
+ reg = <0x2>;
+ qcom,mode = <2>; /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <2>; /* Retention */
+ qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
+ qcom,irqs-detectable;
+ qcom.gpios-detectable;
+ qcom,latency-us = <95>;
+ qcom,ss-power = <725>;
+ qcom,energy-overhead = <99500>;
+ qcom,time-overhead = <130>;
+ };
+
+ qcom,lpm-level@3 {
+ reg = <0x3>;
+ qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <1>; /* GDHS */
+ qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
+ qcom,irqs-detectable;
+ qcom.gpios-detectable;
+ qcom,latency-us = <2000>;
+ qcom,ss-power = <138>;
+ qcom,energy-overhead = <1208400>;
+ qcom,time-overhead = <3200>;
+ };
+
+ qcom,lpm-level@4 {
+ reg = <0x4>;
+ qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <1>; /* GDHS */
+ qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
+ qcom,irqs-detectable;
+ qcom.gpios-detectable;
+ qcom,latency-us = <3000>;
+ qcom,ss-power = <110>;
+ qcom,energy-overhead = <1250300>;
+ qcom,time-overhead = <3500>;
+ };
+
+ qcom,lpm-level@5 {
+ reg = <0x5>;
+ qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <0>; /* OFF */
+ qcom,l2 = <1>; /* GDHS */
+ qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
+ qcom,latency-us = <3000>;
+ qcom,ss-power = <68>;
+ qcom,energy-overhead = <1350200>;
+ qcom,time-overhead = <4000>;
+ };
+
+ qcom,lpm-level@6 {
+ reg = <0x6>;
+ qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <0>; /* OFF */
+ qcom,l2 = <1>; /* GDHS */
+ qcom,vdd-mem-upper-bound = <950000>; /* NORMAL */
+ qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
+ qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
+ qcom,latency-us = <18000>;
+ qcom,ss-power = <10>;
+ qcom,energy-overhead = <3202600>;
+ qcom,time-overhead = <27000>;
+ };
+
+ qcom,lpm-level@7 {
+ reg = <0x7>;
+ qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <0>; /* OFF */
+ qcom,l2 = <0>; /* OFF */
+ qcom,vdd-mem-upper-bound = <950000>; /* SVS SOC */
+ qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
+ qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
+ qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
+ qcom,latency-us = <20000>;
+ qcom,ss-power = <2>;
+ qcom,energy-overhead = <4252000>;
+ qcom,time-overhead = <32000>;
+ };
+ };
+
+ qcom,pm-boot {
+ compatible = "qcom,pm-boot";
+ qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+ };
+
+ qcom,mpm@fc4281d0 {
+ compatible = "qcom,mpm-v2";
+ reg = <0xfc4281d0 0x1000>, /* MSM_RPM_MPM_BASE 4K */
+ <0xf9011008 0x4>; /* MSM_APCS_GCC_BASE 4K */
+ reg-names = "vmpm", "ipc";
+ interrupts = <0 171 1>;
+
+ qcom,ipc-bit-offset = <1>;
+
+ qcom,gic-parent = <&intc>;
+ qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
+ <53 104>, /* mdss_irq */
+ <62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+ <0xff 57>, /* mss_to_apps_irq(0) */
+ <0xff 58>, /* mss_to_apps_irq(1) */
+ <0xff 59>, /* mss_to_apps_irq(2) */
+ <0xff 60>, /* mss_to_apps_irq(3) */
+ <0xff 173>, /* o_wcss_apss_smd_hi */
+ <0xff 174>, /* o_wcss_apss_smd_med */
+ <0xff 175>, /* o_wcss_apss_smd_low */
+ <0xff 176>, /* o_wcss_apss_smsm_irq */
+ <0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
+ <0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
+ <0xff 179>, /* o_wcss_apss_asic_intr
+
+ <0xff 188>, /* lpass_irq_out_apcs(0) */
+ <0xff 189>, /* lpass_irq_out_apcs(1) */
+ <0xff 190>, /* lpass_irq_out_apcs(2) */
+ <0xff 191>, /* lpass_irq_out_apcs(3) */
+ <0xff 192>, /* lpass_irq_out_apcs(4) */
+ <0xff 193>, /* lpass_irq_out_apcs(5) */
+ <0xff 194>, /* lpass_irq_out_apcs(6) */
+ <0xff 195>, /* lpass_irq_out_apcs(7) */
+ <0xff 196>, /* lpass_irq_out_apcs(8) */
+ <0xff 197>, /* lpass_irq_out_apcs(9) */
+ <0xff 200>, /* rpm_ipc(4) */
+ <0xff 201>, /* rpm_ipc(5) */
+ <0xff 202>, /* rpm_ipc(6) */
+ <0xff 203>, /* rpm_ipc(7) */
+ <0xff 204>, /* rpm_ipc(24) */
+ <0xff 205>, /* rpm_ipc(25) */
+ <0xff 206>, /* rpm_ipc(26) */
+ <0xff 207>, /* rpm_ipc(27) */
+ <0xff 240>; /* summary_irq_kpss */
+
+ qcom,gpio-parent = <&msmgpio>;
+ qcom,gpio-map = <3 102>,
+ <4 1 >,
+ <5 5 >,
+ <6 9 >,
+ <7 18>,
+ <8 20>,
+ <9 24>,
+ <10 27>,
+ <11 28>,
+ <12 34>,
+ <13 35>,
+ <14 37>,
+ <15 42>,
+ <16 44>,
+ <17 46>,
+ <18 50>,
+ <19 54>,
+ <20 59>,
+ <21 61>,
+ <22 62>,
+ <23 64>,
+ <24 65>,
+ <25 66>,
+ <26 67>,
+ <27 68>,
+ <28 71>,
+ <29 72>,
+ <30 73>,
+ <31 74>,
+ <32 75>,
+ <33 77>,
+ <34 79>,
+ <35 80>,
+ <36 82>,
+ <37 86>,
+ <38 92>,
+ <39 93>,
+ <40 95>;
+ };
+
+ qcom,pm-8x60@fe805664 {
+ compatible = "qcom,pm-8x60";
+ reg = <0xfe805664 0x40>;
+ qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
+ qcom,use-sync-timer;
+ qcom,saw-turns-off-pll;
+ };
+
+ qcom,rpm-log@fc19dc00 {
+ compatible = "qcom,rpm-log";
+ reg = <0xfc19dc00 0x4000>;
+ qcom,rpm-addr-phys = <0xfc000000>;
+ qcom,offset-version = <4>;
+ qcom,offset-page-buffer-addr = <36>;
+ qcom,offset-log-len = <40>;
+ qcom,offset-log-len-mask = <44>;
+ qcom,offset-page-indices = <56>;
+ };
+
+ qcom,rpm-stats@0xfc19dbd0{
+ compatible = "qcom,rpm-stats";
+ reg = <0xfc19dbd0 0x1000>;
+ reg-names = "phys_addr_base";
+ qcom,sleep-stats-version = <2>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 3dda20f..16cdeb1 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -19,6 +19,7 @@
/include/ "msm8974.dtsi"
/include/ "msm8974-v2-iommu.dtsi"
/include/ "msm8974-v2-iommu-domains.dtsi"
+/include/ "msm8974-v2-pm.dtsi"
/ {
android_usb@fe8050c8 {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 7c6a9d1..ab6b7c8 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -11,7 +11,6 @@
*/
/include/ "skeleton.dtsi"
-/include/ "msm8974-pm.dtsi"
/include/ "msm8974-camera.dtsi"
/include/ "msm8974-coresight.dtsi"
/include/ "msm-gdsc.dtsi"
@@ -29,6 +28,10 @@
aliases {
spi0 = &spi_0;
spi7 = &spi_7;
+ sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
+ sdhc2 = &sdhc_2; /* SDC2 SD card slot */
+ sdhc3 = &sdhc_3; /* SDC3 SDIO slot */
+ sdhc4 = &sdhc_4; /* SDC4 SDIO slot */
};
memory {
@@ -333,6 +336,64 @@
status = "disable";
};
+ sdhc_1: sdhci@f9824900 {
+ qcom,bus-width = <8>;
+ 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";
+ qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+ status = "disable";
+ };
+
+ sdhc_2: sdhci@f98a4900 {
+ compatible = "qcom,sdhci-msm";
+ reg = <0xf98a4900 0x11c>, <0xf98a4000 0x800>;
+ reg-names = "hc_mem", "core_mem";
+ interrupts = <0 125 0>, <0 221 0>;
+ interrupt-names = "hc_irq", "pwr_irq";
+
+ qcom,bus-width = <4>;
+ status = "disable";
+ };
+
+ sdhc_3: sdhci@f9864900 {
+ compatible = "qcom,sdhci-msm";
+ reg = <0xf9864900 0x11c>, <0xf9864000 0x800>;
+ reg-names = "hc_mem", "core_mem";
+ interrupts = <0 127 0>, <0 224 0>;
+ interrupt-names = "hc_irq", "pwr_irq";
+ gpios = <&msmgpio 40 0>, /* CLK */
+ <&msmgpio 39 0>, /* CMD */
+ <&msmgpio 38 0>, /* DATA0 */
+ <&msmgpio 37 0>, /* DATA1 */
+ <&msmgpio 36 0>, /* DATA2 */
+ <&msmgpio 35 0>; /* DATA3 */
+ qcom,gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
+
+ qcom,bus-width = <4>;
+ status = "disable";
+ };
+
+ sdhc_4: sdhci@f98e4900 {
+ compatible = "qcom,sdhci-msm";
+ reg = <0xf98e4900 0x11c>, <0xf98e4000 0x800>;
+ reg-names = "hc_mem", "core_mem";
+ interrupts = <0 129 0>, <0 227 0>;
+ interrupt-names = "hc_irq", "pwr_irq";
+ gpios = <&msmgpio 93 0>, /* CLK */
+ <&msmgpio 91 0>, /* CMD */
+ <&msmgpio 96 0>, /* DATA0 */
+ <&msmgpio 95 0>, /* DATA1 */
+ <&msmgpio 94 0>, /* DATA2 */
+ <&msmgpio 92 0>; /* DATA3 */
+ qcom,gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
+
+ qcom,bus-width = <4>;
+ status = "disable";
+ };
+
qcom,sps@f9980000 {
compatible = "qcom,msm_sps";
reg = <0xf9984000 0x15000>,
@@ -1170,7 +1231,7 @@
qcom,smem@fa00000 {
compatible = "qcom,smem";
reg = <0xfa00000 0x200000>,
- <0xfa006000 0x1000>,
+ <0xf9011000 0x1000>,
<0xfc428000 0x4000>;
reg-names = "smem", "irq-reg-base", "aux-mem1";
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index 1880965..e881977 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -162,6 +162,22 @@
qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <0>; /* OFF */
qcom,l2 = <0>; /* OFF */
+ qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
+ qcom,irqs-detectable;
+ qcom,latency-us = <8000>;
+ qcom,ss-power = <1800>;
+ qcom,energy-overhead = <71950000>;
+ qcom,time-overhead = <15300>;
+ };
+
+ qcom,lpm-level@6 {
+ reg = <0x6>;
+ qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <0>; /* OFF */
+ qcom,l2 = <0>; /* OFF */
qcom,vdd-mem-upper-bound = <950000>; /* SVS SOC */
qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
diff --git a/arch/arm/boot/dts/msm9625-v1.dtsi b/arch/arm/boot/dts/msm9625-v1.dtsi
index 54fe443..54aa02a 100644
--- a/arch/arm/boot/dts/msm9625-v1.dtsi
+++ b/arch/arm/boot/dts/msm9625-v1.dtsi
@@ -49,3 +49,11 @@
&stm {
qcom,write-64bit;
};
+
+&sfpb_spinlock {
+ status = "disable";
+};
+
+&ldrex_spinlock {
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/msm9625-v2.dtsi b/arch/arm/boot/dts/msm9625-v2.dtsi
index c3c2c49..3ce6844 100644
--- a/arch/arm/boot/dts/msm9625-v2.dtsi
+++ b/arch/arm/boot/dts/msm9625-v2.dtsi
@@ -34,3 +34,11 @@
&ipa_hw {
qcom,ipa-hw-ver = <2>; /* IPA h-w revision */
};
+
+&sfpb_spinlock {
+ status = "disable";
+};
+
+&ldrex_spinlock {
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 8517605..e1501ac 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -91,6 +91,7 @@
qcom,hsusb-otg-disable-reset;
qcom,hsusb-otg-lpm-on-dev-suspend;
qcom,hsusb-otg-clk-always-on-workaround;
+ qcom,hsusb-otg-delay-lpm;
qcom,msm-bus,name = "usb2";
qcom,msm-bus,num-cases = <2>;
@@ -104,8 +105,8 @@
hsic@f9a15000 {
compatible = "qcom,hsic-host";
reg = <0xf9a15000 0x400>;
- interrupts = <0 136 0>;
- interrupt-names = "core_irq";
+ interrupts = <0 136 0>, <0 148 0>;
+ interrupt-names = "core_irq", "async_irq";
HSIC_VDDCX-supply = <&pm8019_l12>;
HSIC_GDSC-supply = <&gdsc_usb_hsic>;
@@ -634,7 +635,7 @@
qcom,smem@fa00000 {
compatible = "qcom,smem";
reg = <0xfa00000 0x200000>,
- <0xfa006000 0x1000>,
+ <0xf9011000 0x1000>,
<0xfc428000 0x4000>;
reg-names = "smem", "irq-reg-base", "aux-mem1";
@@ -718,6 +719,18 @@
qcom,memblock-remove = <0x1f00000 0x5700000>; /* Address and Size of Hole */
};
+ sfpb_spinlock: qcom,ipc-spinlock@fd484000 {
+ compatible = "qcom,ipc-spinlock-sfpb";
+ reg = <0xfd484000 0x1000>;
+ qcom,num-locks = <32>;
+ };
+
+ ldrex_spinlock: qcom,ipc-spinlock@fa00000 {
+ compatible = "qcom,ipc-spinlock-ldrex";
+ reg = <0xfa00000 0x200000>;
+ status = "disable";
+ };
+
};
/include/ "msm-pm8019-rpm-regulator.dtsi"
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 8e948c2..8eac20f 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -374,7 +374,6 @@
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_SHIRQ=y
-# CONFIG_SCHED_DEBUG is not set
CONFIG_TIMER_STATS=y
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm7630-perf_defconfig b/arch/arm/configs/msm7630-perf_defconfig
index f2d25ac..e46b835 100644
--- a/arch/arm/configs/msm7630-perf_defconfig
+++ b/arch/arm/configs/msm7630-perf_defconfig
@@ -372,7 +372,6 @@
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_FS=y
-# CONFIG_SCHED_DEBUG is not set
CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index df4ae19..14bd1b4 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -114,6 +114,8 @@
CONFIG_NET_SCH_HTB=y
CONFIG_NET_SCH_PRIO=y
CONFIG_NET_CLS_FW=y
+CONFIG_SYNC=y
+CONFIG_SW_SYNC=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_MD=y
@@ -151,6 +153,9 @@
CONFIG_WCD9306_CODEC=y
CONFIG_GPIO_QPNP_PIN=y
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
@@ -160,7 +165,14 @@
CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
CONFIG_FB=y
-CONFIG_FB_VIRTUAL=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_SOC=y
@@ -185,11 +197,15 @@
CONFIG_ANDROID_RAM_CONSOLE=y
CONFIG_ANDROID_TIMED_GPIO=y
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_QPNP_PWM=y
CONFIG_MSM_IOMMU=y
CONFIG_MSM_IOMMU_PMON=y
CONFIG_SPS=y
CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_QPNP=y
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_MSM is not set
CONFIG_RTC_DRV_QPNP=y
@@ -238,3 +254,12 @@
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8974=y
CONFIG_THERMAL_MONITOR=y
+CONFIG_MSM_RTB=y
+CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_TMC=y
+CONFIG_CORESIGHT_TPIU=y
+CONFIG_CORESIGHT_FUNNEL=y
+CONFIG_CORESIGHT_REPLICATOR=y
+CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_EVENT=m
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index 828484a..baefac5 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -438,7 +438,6 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
-# CONFIG_SCHED_DEBUG is not set
CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 7362ea0..8232a8d 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -510,7 +510,6 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
-# CONFIG_SCHED_DEBUG is not set
CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index d36d5a2..c6be3c5 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -393,6 +393,7 @@
CONFIG_MMC_BLOCK_TEST=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_MSM=y
CONFIG_MMC_MSM=y
CONFIG_MMC_MSM_SPS_SUPPORT=y
CONFIG_LEDS_QPNP=y
@@ -429,6 +430,8 @@
CONFIG_CORESIGHT_ETM=y
CONFIG_CORESIGHT_ETM_PCSAVE_DEFAULT_ENABLE=y
CONFIG_CORESIGHT_EVENT=m
+CONFIG_BIF=y
+CONFIG_BIF_QPNP=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
@@ -442,7 +445,6 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
-# CONFIG_SCHED_DEBUG is not set
CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index df0b5f0..f77f04f 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -401,6 +401,7 @@
CONFIG_MMC_BLOCK_TEST=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_MSM=y
CONFIG_MMC_MSM=y
CONFIG_MMC_MSM_SPS_SUPPORT=y
CONFIG_LEDS_QPNP=y
@@ -438,6 +439,8 @@
CONFIG_CORESIGHT_ETM=y
CONFIG_CORESIGHT_ETM_PCSAVE_DEFAULT_ENABLE=y
CONFIG_CORESIGHT_EVENT=m
+CONFIG_BIF=y
+CONFIG_BIF_QPNP=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 938be62..c1295c4 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -68,15 +68,18 @@
#define __raw_writeb_no_log(v, a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a) = (v))
#define __raw_writew_no_log(v, a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v))
#define __raw_writel_no_log(v, a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v))
+#define __raw_writell_no_log(v, a) (__chk_io_ptr(a), *(volatile unsigned long long __force *)(a) = (v))
#define __raw_writeb(v, a) __raw_write_logged((v), (a), b)
#define __raw_writew(v, a) __raw_write_logged((v), (a), w)
#define __raw_writel(v, a) __raw_write_logged((v), (a), l)
+#define __raw_writell(v, a) __raw_write_logged((v), (a), ll)
#define __raw_readb_no_log(a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a))
#define __raw_readw_no_log(a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a))
#define __raw_readl_no_log(a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a))
+#define __raw_readll_no_log(a) (__chk_io_ptr(a), *(volatile unsigned long long __force *)(a))
#define __raw_read_logged(a, _l, _t) ({ \
unsigned _t __a; \
@@ -94,6 +97,7 @@
#define __raw_readb(a) __raw_read_logged((a), b, char)
#define __raw_readw(a) __raw_read_logged((a), w, short)
#define __raw_readl(a) __raw_read_logged((a), l, int)
+#define __raw_readll(a) __raw_read_logged((a), ll, long long)
/*
* Architecture ioremap implementation.
@@ -268,8 +272,12 @@
__raw_readw(c)); __r; })
#define readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32) \
__raw_readl(c)); __r; })
+#define readll_relaxed(c) ({ u64 __r = le64_to_cpu((__force __le64) \
+ __raw_readll(c)); __r; })
#define readl_relaxed_no_log(c) ({ u32 __r = le32_to_cpu((__force __le32) \
__raw_readl_no_log(c)); __r; })
+#define readll_relaxed_no_log(c) ({ u64 __r = le64_to_cpu((__force __le64) \
+ __raw_readll_no_log(c)); __r; })
#define writeb_relaxed(v,c) ((void)__raw_writeb(v,c))
@@ -277,16 +285,22 @@
cpu_to_le16(v),c))
#define writel_relaxed(v,c) ((void)__raw_writel((__force u32) \
cpu_to_le32(v),c))
+#define writell_relaxed(v, c) ((void)__raw_writell((__force u64) \
+ cpu_to_le64(v), c))
#define writel_relaxed_no_log(v, c) ((void)__raw_writel_no_log((__force u32) \
cpu_to_le32(v), c))
+#define writell_relaxed_no_log(v, c) ((void)__raw_writell_no_log((__force u64) \
+ cpu_to_le64(v), c))
#define readb(c) ({ u8 __v = readb_relaxed(c); __iormb(); __v; })
#define readw(c) ({ u16 __v = readw_relaxed(c); __iormb(); __v; })
#define readl(c) ({ u32 __v = readl_relaxed(c); __iormb(); __v; })
+#define readll(c) ({ u64 __v = readll_relaxed(c); __iormb(); __v; })
#define writeb(v,c) ({ __iowmb(); writeb_relaxed(v,c); })
#define writew(v,c) ({ __iowmb(); writew_relaxed(v,c); })
#define writel(v,c) ({ __iowmb(); writel_relaxed(v,c); })
+#define writell(v, c) ({ __iowmb(); writell_relaxed(v, c); })
#define readsb(p,d,l) __raw_readsb(p,d,l)
#define readsw(p,d,l) __raw_readsw(p,d,l)
@@ -316,22 +330,26 @@
#define iounmap __arm_iounmap
/*
- * io{read,write}{8,16,32} macros
+ * io{read,write}{8,16,32,64} macros
*/
#ifndef ioread8
#define ioread8(p) ({ unsigned int __v = __raw_readb(p); __iormb(); __v; })
#define ioread16(p) ({ unsigned int __v = le16_to_cpu((__force __le16)__raw_readw(p)); __iormb(); __v; })
#define ioread32(p) ({ unsigned int __v = le32_to_cpu((__force __le32)__raw_readl(p)); __iormb(); __v; })
+#define ioread64(p) ({ unsigned int __v = le64_to_cpu((__force __le64)__raw_readll(p)); __iormb(); __v; })
#define ioread16be(p) ({ unsigned int __v = be16_to_cpu((__force __be16)__raw_readw(p)); __iormb(); __v; })
#define ioread32be(p) ({ unsigned int __v = be32_to_cpu((__force __be32)__raw_readl(p)); __iormb(); __v; })
+#define ioread64be(p) ({ unsigned int __v = be64_to_cpu((__force __be64)__raw_readll(p)); __iormb(); __v; })
#define iowrite8(v,p) ({ __iowmb(); (void)__raw_writeb(v, p); })
#define iowrite16(v,p) ({ __iowmb(); (void)__raw_writew((__force __u16)cpu_to_le16(v), p); })
#define iowrite32(v,p) ({ __iowmb(); (void)__raw_writel((__force __u32)cpu_to_le32(v), p); })
+#define iowrite64(v, p) ({ __iowmb(); (void)__raw_writell((__force __u64)cpu_to_le64(v), p); })
#define iowrite16be(v,p) ({ __iowmb(); (void)__raw_writew((__force __u16)cpu_to_be16(v), p); })
#define iowrite32be(v,p) ({ __iowmb(); (void)__raw_writel((__force __u32)cpu_to_be32(v), p); })
+#define iowrite64be(v, p) ({ __iowmb(); (void)__raw_writell((__force __u64)cpu_to_be64(v), p); })
#define ioread8_rep(p,d,c) __raw_readsb(p,d,c)
#define ioread16_rep(p,d,c) __raw_readsw(p,d,c)
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index b10212e..1b36410 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -50,13 +50,7 @@
select MSM_REMOTE_SPINLOCK_DEKKERS
select ARCH_SPARSEMEM_ENABLE
select ARCH_HAS_HOLES_MEMORYMODEL
- select MEMORY_HOTPLUG
- select MEMORY_HOTREMOVE
- select ARCH_ENABLE_MEMORY_HOTPLUG
- select ARCH_ENABLE_MEMORY_HOTREMOVE
select MIGRATION
- select ARCH_MEMORY_PROBE
- select ARCH_MEMORY_REMOVE
select MSM_GPIOMUX
select RESERVE_FIRST_PAGE
select MSM_DALRPC
diff --git a/arch/arm/mach-msm/avs.c b/arch/arm/mach-msm/avs.c
index aa257ef..b2185e3 100644
--- a/arch/arm/mach-msm/avs.c
+++ b/arch/arm/mach-msm/avs.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -16,6 +16,7 @@
#include <asm/mach-types.h>
#include <asm/cputype.h>
#include "avs.h"
+#include "spm.h"
u32 avs_get_avscsr(void)
{
@@ -72,7 +73,10 @@
static void avs_disable_local(void *data)
{
+ int cpu = smp_processor_id();
+
avs_set_avscsr(0);
+ msm_spm_set_vdd(cpu, msm_spm_get_vdd(cpu));
}
void avs_enable(int cpu, u32 avsdscr)
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index f3d648e..1d07356 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -683,53 +683,6 @@
.paddr_to_memtype = apq8064_paddr_to_memtype,
};
-static int apq8064_memory_bank_size(void)
-{
- return 1<<29;
-}
-
-static void __init locate_unstable_memory(void)
-{
- struct membank *mb = &meminfo.bank[meminfo.nr_banks - 1];
- unsigned long bank_size;
- unsigned long low, high;
-
- bank_size = apq8064_memory_bank_size();
- low = meminfo.bank[0].start;
- high = mb->start + mb->size;
-
- /* Check if 32 bit overflow occured */
- if (high < mb->start)
- high = -PAGE_SIZE;
-
- low &= ~(bank_size - 1);
-
- if (high - low <= bank_size)
- goto no_dmm;
-
-#ifdef CONFIG_ENABLE_DMM
- apq8064_reserve_info.low_unstable_address = mb->start -
- MIN_MEMORY_BLOCK_SIZE + mb->size;
- apq8064_reserve_info.max_unstable_size = MIN_MEMORY_BLOCK_SIZE;
-
- apq8064_reserve_info.bank_size = bank_size;
- pr_info("low unstable address %lx max size %lx bank size %lx\n",
- apq8064_reserve_info.low_unstable_address,
- apq8064_reserve_info.max_unstable_size,
- apq8064_reserve_info.bank_size);
- return;
-#endif
-no_dmm:
- apq8064_reserve_info.low_unstable_address = high;
- apq8064_reserve_info.max_unstable_size = 0;
-}
-
-static int apq8064_change_memory_power(u64 start, u64 size,
- int change_type)
-{
- return soc_change_memory_power(start, size, change_type);
-}
-
static char prim_panel_name[PANEL_NAME_MAX_LEN];
static char ext_panel_name[PANEL_NAME_MAX_LEN];
@@ -766,22 +719,9 @@
msm_reserve();
}
-static void __init place_movable_zone(void)
-{
-#ifdef CONFIG_ENABLE_DMM
- movable_reserved_start = apq8064_reserve_info.low_unstable_address;
- movable_reserved_size = apq8064_reserve_info.max_unstable_size;
- pr_info("movable zone start %lx size %lx\n",
- movable_reserved_start, movable_reserved_size);
-#endif
-}
-
static void __init apq8064_early_reserve(void)
{
reserve_info = &apq8064_reserve_info;
- locate_unstable_memory();
- place_movable_zone();
-
}
#ifdef CONFIG_USB_EHCI_MSM_HSIC
/* Bandwidth requests (zero) if no vote placed */
@@ -3935,8 +3875,6 @@
if (machine_is_apq8064_mtp())
platform_device_register(&mtp_kp_pdev);
- change_memory_power = &apq8064_change_memory_power;
-
if (machine_is_mpq8064_cdp()) {
platform_device_register(&mpq_gpio_keys_pdev);
platform_device_register(&mpq_keypad_device);
@@ -3979,7 +3917,6 @@
#ifdef CONFIG_MSM_CAMERA
apq8064_init_cam();
#endif
- change_memory_power = &apq8064_change_memory_power;
}
MACHINE_START(APQ8064_CDP, "QCT APQ8064 CDP")
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 8be5525..c1971c1 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -93,6 +93,28 @@
},
};
+static struct gpiomux_setting sd_card_det_active_config = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ .dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting sd_card_det_sleep_config = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+ .dir = GPIOMUX_IN,
+};
+
+static struct msm_gpiomux_config sd_card_det __initdata = {
+ .gpio = 38,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sd_card_det_active_config,
+ [GPIOMUX_SUSPENDED] = &sd_card_det_sleep_config,
+ },
+};
+
void __init msm8226_init_gpiomux(void)
{
int rc;
@@ -108,4 +130,6 @@
#endif
msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+
+ msm_gpiomux_install(&sd_card_det, 1);
}
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index fbcc6f1..73b4eb7 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -714,64 +714,9 @@
.paddr_to_memtype = msm8930_paddr_to_memtype,
};
-static int msm8930_memory_bank_size(void)
-{
- return 1<<29;
-}
-
-static void __init locate_unstable_memory(void)
-{
- struct membank *mb = &meminfo.bank[meminfo.nr_banks - 1];
- unsigned long bank_size;
- unsigned long low, high;
-
- bank_size = msm8930_memory_bank_size();
- low = meminfo.bank[0].start;
- high = mb->start + mb->size;
-
- /* Check if 32 bit overflow occured */
- if (high < mb->start)
- high -= PAGE_SIZE;
-
- if (high < MAX_FIXED_AREA_SIZE + MSM8930_FIXED_AREA_START)
- panic("fixed area extends beyond end of memory\n");
-
- low &= ~(bank_size - 1);
-
- if (high - low <= bank_size)
- goto no_dmm;
-
- msm8930_reserve_info.bank_size = bank_size;
-#ifdef CONFIG_ENABLE_DMM
- msm8930_reserve_info.low_unstable_address = mb->start -
- MIN_MEMORY_BLOCK_SIZE + mb->size;
- msm8930_reserve_info.max_unstable_size = MIN_MEMORY_BLOCK_SIZE;
- pr_info("low unstable address %lx max size %lx bank size %lx\n",
- msm8930_reserve_info.low_unstable_address,
- msm8930_reserve_info.max_unstable_size,
- msm8930_reserve_info.bank_size);
- return;
-#endif
-no_dmm:
- msm8930_reserve_info.low_unstable_address = high;
- msm8930_reserve_info.max_unstable_size = 0;
-}
-
-static void __init place_movable_zone(void)
-{
-#ifdef CONFIG_ENABLE_DMM
- movable_reserved_start = msm8930_reserve_info.low_unstable_address;
- movable_reserved_size = msm8930_reserve_info.max_unstable_size;
- pr_info("movable zone start %lx size %lx\n",
- movable_reserved_start, movable_reserved_size);
-#endif
-}
-
static void __init msm8930_early_memory(void)
{
reserve_info = &msm8930_reserve_info;
- locate_unstable_memory();
- place_movable_zone();
}
static char prim_panel_name[PANEL_NAME_MAX_LEN];
@@ -799,12 +744,6 @@
msm_reserve();
}
-static int msm8930_change_memory_power(u64 start, u64 size,
- int change_type)
-{
- return soc_change_memory_power(start, size, change_type);
-}
-
static void __init msm8930_allocate_memory_regions(void)
{
msm8930_allocate_fb_region();
@@ -3022,7 +2961,6 @@
msm8930_init_fb();
slim_register_board_info(msm_slim_devices,
ARRAY_SIZE(msm_slim_devices));
- change_memory_power = &msm8930_change_memory_power;
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
if (PLATFORM_IS_CHARM25())
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 3df0b38..bd54756 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -806,65 +806,9 @@
.paddr_to_memtype = msm8960_paddr_to_memtype,
};
-static int msm8960_memory_bank_size(void)
-{
- return 1<<29;
-}
-
-static void __init locate_unstable_memory(void)
-{
- struct membank *mb = &meminfo.bank[meminfo.nr_banks - 1];
- unsigned long bank_size;
- unsigned long low, high;
-
- bank_size = msm8960_memory_bank_size();
- msm8960_reserve_info.bank_size = bank_size;
-
- low = meminfo.bank[0].start;
- high = mb->start + mb->size;
-
- /* Check if 32 bit overflow occured */
- if (high < mb->start)
- high = ~0UL;
-
- if (high < MAX_FIXED_AREA_SIZE + MSM8960_FIXED_AREA_START)
- panic("fixed area extends beyond end of memory\n");
-
- low &= ~(bank_size - 1);
-
- if (high - low <= bank_size)
- goto no_dmm;
-
-#ifdef CONFIG_ENABLE_DMM
- msm8960_reserve_info.low_unstable_address = mb->start -
- MIN_MEMORY_BLOCK_SIZE + mb->size;
- msm8960_reserve_info.max_unstable_size = MIN_MEMORY_BLOCK_SIZE;
- pr_info("low unstable address %lx max size %lx bank size %lx\n",
- msm8960_reserve_info.low_unstable_address,
- msm8960_reserve_info.max_unstable_size,
- msm8960_reserve_info.bank_size);
- return;
-#endif
-no_dmm:
- msm8960_reserve_info.low_unstable_address = high;
- msm8960_reserve_info.max_unstable_size = 0;
-}
-
-static void __init place_movable_zone(void)
-{
-#ifdef CONFIG_ENABLE_DMM
- movable_reserved_start = msm8960_reserve_info.low_unstable_address;
- movable_reserved_size = msm8960_reserve_info.max_unstable_size;
- pr_info("movable zone start %lx size %lx\n",
- movable_reserved_start, movable_reserved_size);
-#endif
-}
-
static void __init msm8960_early_memory(void)
{
reserve_info = &msm8960_reserve_info;
- locate_unstable_memory();
- place_movable_zone();
}
static char prim_panel_name[PANEL_NAME_MAX_LEN];
@@ -891,12 +835,6 @@
msm_reserve();
}
-static int msm8960_change_memory_power(u64 start, u64 size,
- int change_type)
-{
- return soc_change_memory_power(start, size, change_type);
-}
-
static void __init msm8960_allocate_memory_regions(void)
{
msm8960_allocate_fb_region();
@@ -3556,7 +3494,6 @@
slim_register_board_info(msm_slim_devices,
ARRAY_SIZE(msm_slim_devices));
msm8960_init_dsps();
- change_memory_power = &msm8960_change_memory_power;
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
bt_power_init();
if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 119eeb2..b40617c 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -60,6 +60,8 @@
#define gpll0_mm_source_val 5
#define dsipll_750_mm_source_val 1
#define dsipll_667_mm_source_val 1
+#define dsipll0_byte_mm_source_val 1
+#define dsipll0_pixel_mm_source_val 1
#define gpll1_hsic_source_val 4
@@ -1801,21 +1803,36 @@
},
};
-static struct clk_freq_tbl ftbl_mdss_pclk0_clk[] = {
- F_MDSS( 83000000, dsipll_667, 8, 0, 0),
- F_MDSS( 166000000, dsipll_667, 4, 0, 0),
- F_END
+static struct branch_clk mdss_ahb_clk;
+static struct clk dsipll0_byte_clk_src = {
+ .depends = &mdss_ahb_clk.c,
+ .parent = &xo.c,
+ .dbg_name = "dsipll0_byte_clk_src",
+ .ops = &clk_ops_dsi_byte_pll,
+ CLK_INIT(dsipll0_byte_clk_src),
+};
+
+static struct clk dsipll0_pixel_clk_src = {
+ .depends = &mdss_ahb_clk.c,
+ .parent = &xo.c,
+ .dbg_name = "dsipll0_pixel_clk_src",
+ .ops = &clk_ops_dsi_pixel_pll,
+ CLK_INIT(dsipll0_pixel_clk_src),
+};
+
+static struct clk_freq_tbl pixel_freq = {
+ .src_clk = &dsipll0_pixel_clk_src,
+ .div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val),
};
static struct rcg_clk pclk0_clk_src = {
.cmd_rcgr_reg = PCLK0_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_mdss_pclk0_clk,
- .current_freq = &rcg_dummy_freq,
+ .current_freq = &pixel_freq,
.base = &virt_bases[MMSS_BASE],
.c = {
+ .parent = &dsipll0_pixel_clk_src,
.dbg_name = "pclk0_clk_src",
- .ops = &clk_ops_rcg_mnd,
+ .ops = &clk_ops_pixel,
VDD_DIG_FMAX_MAP2(LOW, 83330000, NOMINAL, 166670000),
CLK_INIT(pclk0_clk_src.c),
},
@@ -1990,21 +2007,19 @@
},
};
-static struct clk_freq_tbl ftbl_mdss_byte0_clk[] = {
- F_MDSS( 62500000, dsipll_750, 12, 0, 0),
- F_MDSS( 125000000, dsipll_750, 6, 0, 0),
- F_END
+static struct clk_freq_tbl byte_freq = {
+ .src_clk = &dsipll0_byte_clk_src,
+ .div_src_val = BVAL(10, 8, dsipll0_byte_mm_source_val),
};
static struct rcg_clk byte0_clk_src = {
.cmd_rcgr_reg = BYTE0_CMD_RCGR,
- .set_rate = set_rate_hid,
- .freq_tbl = ftbl_mdss_byte0_clk,
- .current_freq = &rcg_dummy_freq,
+ .current_freq = &byte_freq,
.base = &virt_bases[MMSS_BASE],
.c = {
+ .parent = &dsipll0_byte_clk_src,
.dbg_name = "byte0_clk_src",
- .ops = &clk_ops_rcg,
+ .ops = &clk_ops_byte,
VDD_DIG_FMAX_MAP2(LOW, 62500000, NOMINAL, 125000000),
CLK_INIT(byte0_clk_src.c),
},
@@ -3197,12 +3212,12 @@
CLK_LOOKUP("pixel_clk", mdss_pclk0_clk.c, "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "mdss_dsi_clk_ctrl"),
- CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "mdp.0"),
- CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "mdp.0"),
- CLK_LOOKUP("core_clk_src", mdp_clk_src.c, "mdp.0"),
- CLK_LOOKUP("vsync_clk", mdss_vsync_clk.c, "mdp.0"),
- CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "mdp.0"),
- CLK_LOOKUP("bus_clk", mdss_axi_clk.c, "mdp.0"),
+ CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "fd900000.qcom,mdss_mdp"),
+ CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "fd900000.qcom,mdss_mdp"),
+ CLK_LOOKUP("core_clk_src", mdp_clk_src.c, "fd900000.qcom,mdss_mdp"),
+ CLK_LOOKUP("vsync_clk", mdss_vsync_clk.c, "fd900000.qcom,mdss_mdp"),
+ CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd900000.qcom,mdss_mdp"),
+ CLK_LOOKUP("bus_clk", mdss_axi_clk.c, "fd900000.qcom,mdss_mdp"),
CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd928000.qcom,iommu"),
CLK_LOOKUP("core_clk", mdss_axi_clk.c, "fd928000.qcom,iommu"),
@@ -3463,6 +3478,12 @@
enable_rpm_scaling();
reg_init();
+
+ /*
+ * MDSS needs the ahb clock and needs to init before we register the
+ * lookup table.
+ */
+ mdss_clk_ctrl_pre_init(&mdss_ahb_clk.c);
}
static int __init msm8226_clock_late_init(void)
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 4cef377..3587df6 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -3030,134 +3030,6 @@
.src_clk = &dsipll0_byte_clk_src,
.div_src_val = BVAL(10, 8, dsipll0_byte_mm_source_val),
};
-static struct clk_freq_tbl pixel_freq = {
- .src_clk = &dsipll0_pixel_clk_src,
- .div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val),
-};
-static struct clk_ops clk_ops_byte;
-static struct clk_ops clk_ops_pixel;
-
-#define CFG_RCGR_DIV_MASK BM(4, 0)
-#define CMD_RCGR_REG(x) (*(x)->base + (x)->cmd_rcgr_reg + 0x0)
-#define CFG_RCGR_REG(x) (*(x)->base + (x)->cmd_rcgr_reg + 0x4)
-#define M_REG(x) (*(x)->base + (x)->cmd_rcgr_reg + 0x8)
-#define N_REG(x) (*(x)->base + (x)->cmd_rcgr_reg + 0xC)
-#define MND_MODE_MASK BM(13, 12)
-#define MND_DUAL_EDGE_MODE_BVAL BVAL(13, 12, 0x2)
-#define CFG_RCGR_SRC_SEL_MASK BM(10, 8)
-#define CMD_RCGR_ROOT_STATUS_BIT BIT(31)
-
-static enum handoff byte_rcg_handoff(struct clk *clk)
-{
- struct rcg_clk *rcg = to_rcg_clk(clk);
- u32 div_val;
- unsigned long pre_div_rate, parent_rate = clk_get_rate(clk->parent);
-
- /* If the pre-divider is used, find the rate after the division */
- div_val = readl_relaxed(CFG_RCGR_REG(rcg)) & CFG_RCGR_DIV_MASK;
- if (div_val > 1)
- pre_div_rate = parent_rate / ((div_val + 1) >> 1);
- else
- pre_div_rate = parent_rate;
-
- clk->rate = pre_div_rate;
-
- if (readl_relaxed(CMD_RCGR_REG(rcg)) & CMD_RCGR_ROOT_STATUS_BIT)
- return HANDOFF_DISABLED_CLK;
-
- return HANDOFF_ENABLED_CLK;
-}
-
-static int set_rate_byte(struct clk *clk, unsigned long rate)
-{
- struct rcg_clk *rcg = to_rcg_clk(clk);
- struct clk *pll = clk->parent;
- unsigned long source_rate, div;
- int rc;
-
- if (rate == 0)
- return -EINVAL;
-
- rc = clk_set_rate(pll, rate);
- if (rc)
- return rc;
-
- source_rate = clk_round_rate(pll, rate);
- if ((2 * source_rate) % rate)
- return -EINVAL;
-
- div = ((2 * source_rate)/rate) - 1;
- if (div > CFG_RCGR_DIV_MASK)
- return -EINVAL;
-
- byte_freq.div_src_val &= ~CFG_RCGR_DIV_MASK;
- byte_freq.div_src_val |= BVAL(4, 0, div);
- set_rate_hid(rcg, &byte_freq);
-
- return 0;
-}
-
-static enum handoff pixel_rcg_handoff(struct clk *clk)
-{
- struct rcg_clk *rcg = to_rcg_clk(clk);
- u32 div_val, mval, nval, cfg_regval;
- unsigned long pre_div_rate, parent_rate = clk_get_rate(clk->parent);
-
- cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg));
-
- /* If the pre-divider is used, find the rate after the division */
- div_val = cfg_regval & CFG_RCGR_DIV_MASK;
- if (div_val > 1)
- pre_div_rate = parent_rate / ((div_val + 1) >> 1);
- else
- pre_div_rate = parent_rate;
-
- clk->rate = pre_div_rate;
-
- /* If MND is used, find the rate after the MND division */
- if ((cfg_regval & MND_MODE_MASK) == MND_DUAL_EDGE_MODE_BVAL) {
- mval = readl_relaxed(M_REG(rcg));
- nval = readl_relaxed(N_REG(rcg));
- if (!nval)
- return HANDOFF_DISABLED_CLK;
- nval = (~nval) + mval;
- clk->rate = (pre_div_rate * mval) / nval;
- }
-
- if (readl_relaxed(CMD_RCGR_REG(rcg)) & CMD_RCGR_ROOT_STATUS_BIT)
- return HANDOFF_DISABLED_CLK;
-
- return HANDOFF_ENABLED_CLK;
-}
-
-static int set_rate_pixel(struct clk *clk, unsigned long rate)
-{
- struct rcg_clk *rcg = to_rcg_clk(clk);
- struct clk *pll = clk->parent;
- unsigned long source_rate, div;
- int rc;
-
- if (rate == 0)
- return -EINVAL;
-
- rc = clk_set_rate(pll, rate);
- if (rc)
- return rc;
-
- source_rate = clk_round_rate(pll, rate);
- if ((2 * source_rate) % rate)
- return -EINVAL;
-
- div = ((2 * source_rate)/rate) - 1;
- if (div > CFG_RCGR_DIV_MASK)
- return -EINVAL;
-
- pixel_freq.div_src_val &= ~CFG_RCGR_DIV_MASK;
- pixel_freq.div_src_val |= BVAL(4, 0, div);
- set_rate_mnd(rcg, &pixel_freq);
-
- return 0;
-}
static struct rcg_clk byte0_clk_src = {
.cmd_rcgr_reg = BYTE0_CMD_RCGR,
@@ -3324,35 +3196,6 @@
F_END
};
-/*
- * Unlike other clocks, the HDMI rate is adjusted through PLL
- * re-programming. It is also routed through an HID divider.
- */
-static int rcg_clk_set_rate_hdmi(struct clk *c, unsigned long rate)
-{
- struct clk_freq_tbl *nf;
- struct rcg_clk *rcg = to_rcg_clk(c);
- int rc;
-
- for (nf = rcg->freq_tbl; nf->freq_hz != rate; nf++)
- if (nf->freq_hz == FREQ_END) {
- rc = -EINVAL;
- goto out;
- }
-
- rc = clk_set_rate(nf->src_clk, rate);
- if (rc < 0)
- goto out;
- set_rate_hid(rcg, nf);
-
- rcg->current_freq = nf;
- c->parent = nf->src_clk;
-out:
- return rc;
-}
-
-static struct clk_ops clk_ops_rcg_hdmi;
-
static struct rcg_clk extpclk_clk_src = {
.cmd_rcgr_reg = EXTPCLK_CMD_RCGR,
.freq_tbl = ftbl_mdss_extpclk_clk,
@@ -3385,6 +3228,10 @@
},
};
+static struct clk_freq_tbl pixel_freq = {
+ .src_clk = &dsipll0_pixel_clk_src,
+ .div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val),
+};
static struct rcg_clk pclk0_clk_src = {
.cmd_rcgr_reg = PCLK0_CMD_RCGR,
@@ -5525,28 +5372,6 @@
writel_relaxed(0x0, GCC_REG_BASE(APCS_CLOCK_SLEEP_ENA_VOTE));
}
-static void __init mdss_clock_setup(void)
-{
- clk_ops_byte = clk_ops_rcg;
- clk_ops_byte.set_rate = set_rate_byte;
- clk_ops_byte.handoff = byte_rcg_handoff;
- clk_ops_byte.get_parent = NULL;
-
- clk_ops_pixel = clk_ops_rcg_mnd;
- clk_ops_pixel.set_rate = set_rate_pixel;
- clk_ops_pixel.handoff = pixel_rcg_handoff;
- clk_ops_pixel.get_parent = NULL;
-
- clk_ops_rcg_hdmi = clk_ops_rcg;
- clk_ops_rcg_hdmi.set_rate = rcg_clk_set_rate_hdmi;
-
- /*
- * MDSS needs the ahb clock and needs to init before we register the
- * lookup table.
- */
- mdss_clk_ctrl_pre_init(&mdss_ahb_clk.c);
-}
-
static void __init msm8974_clock_post_init(void)
{
if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) {
@@ -5693,7 +5518,11 @@
qup_i2c_clks[i][0]->parent = qup_i2c_clks[i][1];
}
- mdss_clock_setup();
+ /*
+ * MDSS needs the ahb clock and needs to init before we register the
+ * lookup table.
+ */
+ mdss_clk_ctrl_pre_init(&mdss_ahb_clk.c);
}
static int __init msm8974_clock_late_init(void)
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index dd78557..214d1b7 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -624,6 +624,148 @@
return HANDOFF_ENABLED_CLK;
}
+static enum handoff byte_rcg_handoff(struct clk *clk)
+{
+ struct rcg_clk *rcg = to_rcg_clk(clk);
+ u32 div_val;
+ unsigned long pre_div_rate, parent_rate = clk_get_rate(clk->parent);
+
+ /* If the pre-divider is used, find the rate after the division */
+ div_val = readl_relaxed(CFG_RCGR_REG(rcg)) & CFG_RCGR_DIV_MASK;
+ if (div_val > 1)
+ pre_div_rate = parent_rate / ((div_val + 1) >> 1);
+ else
+ pre_div_rate = parent_rate;
+
+ clk->rate = pre_div_rate;
+
+ if (readl_relaxed(CMD_RCGR_REG(rcg)) & CMD_RCGR_ROOT_STATUS_BIT)
+ return HANDOFF_DISABLED_CLK;
+
+ return HANDOFF_ENABLED_CLK;
+}
+
+static int set_rate_byte(struct clk *clk, unsigned long rate)
+{
+ struct rcg_clk *rcg = to_rcg_clk(clk);
+ struct clk *pll = clk->parent;
+ unsigned long source_rate, div;
+ struct clk_freq_tbl *byte_freq = rcg->current_freq;
+ int rc;
+
+ if (rate == 0)
+ return -EINVAL;
+
+ rc = clk_set_rate(pll, rate);
+ if (rc)
+ return rc;
+
+ source_rate = clk_round_rate(pll, rate);
+ if ((2 * source_rate) % rate)
+ return -EINVAL;
+
+ div = ((2 * source_rate)/rate) - 1;
+ if (div > CFG_RCGR_DIV_MASK)
+ return -EINVAL;
+
+ byte_freq->div_src_val &= ~CFG_RCGR_DIV_MASK;
+ byte_freq->div_src_val |= BVAL(4, 0, div);
+ set_rate_hid(rcg, byte_freq);
+
+ return 0;
+}
+
+static enum handoff pixel_rcg_handoff(struct clk *clk)
+{
+ struct rcg_clk *rcg = to_rcg_clk(clk);
+ u32 div_val, mval, nval, cfg_regval;
+ unsigned long pre_div_rate, parent_rate = clk_get_rate(clk->parent);
+
+ cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg));
+
+ /* If the pre-divider is used, find the rate after the division */
+ div_val = cfg_regval & CFG_RCGR_DIV_MASK;
+ if (div_val > 1)
+ pre_div_rate = parent_rate / ((div_val + 1) >> 1);
+ else
+ pre_div_rate = parent_rate;
+
+ clk->rate = pre_div_rate;
+
+ /* If MND is used, find the rate after the MND division */
+ if ((cfg_regval & MND_MODE_MASK) == MND_DUAL_EDGE_MODE_BVAL) {
+ mval = readl_relaxed(M_REG(rcg));
+ nval = readl_relaxed(N_REG(rcg));
+ if (!nval)
+ return HANDOFF_DISABLED_CLK;
+ nval = (~nval) + mval;
+ clk->rate = (pre_div_rate * mval) / nval;
+ }
+
+ if (readl_relaxed(CMD_RCGR_REG(rcg)) & CMD_RCGR_ROOT_STATUS_BIT)
+ return HANDOFF_DISABLED_CLK;
+
+ return HANDOFF_ENABLED_CLK;
+}
+
+static int set_rate_pixel(struct clk *clk, unsigned long rate)
+{
+ struct rcg_clk *rcg = to_rcg_clk(clk);
+ struct clk *pll = clk->parent;
+ unsigned long source_rate, div;
+ struct clk_freq_tbl *pixel_freq = rcg->current_freq;
+ int rc;
+
+ if (rate == 0)
+ return -EINVAL;
+
+ rc = clk_set_rate(pll, rate);
+ if (rc)
+ return rc;
+
+ source_rate = clk_round_rate(pll, rate);
+ if ((2 * source_rate) % rate)
+ return -EINVAL;
+
+ div = ((2 * source_rate)/rate) - 1;
+ if (div > CFG_RCGR_DIV_MASK)
+ return -EINVAL;
+
+ pixel_freq->div_src_val &= ~CFG_RCGR_DIV_MASK;
+ pixel_freq->div_src_val |= BVAL(4, 0, div);
+ set_rate_mnd(rcg, pixel_freq);
+
+ return 0;
+}
+
+/*
+ * Unlike other clocks, the HDMI rate is adjusted through PLL
+ * re-programming. It is also routed through an HID divider.
+ */
+static int rcg_clk_set_rate_hdmi(struct clk *c, unsigned long rate)
+{
+ struct clk_freq_tbl *nf;
+ struct rcg_clk *rcg = to_rcg_clk(c);
+ int rc;
+
+ for (nf = rcg->freq_tbl; nf->freq_hz != rate; nf++)
+ if (nf->freq_hz == FREQ_END) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = clk_set_rate(nf->src_clk, rate);
+ if (rc < 0)
+ goto out;
+ set_rate_hid(rcg, nf);
+
+ rcg->current_freq = nf;
+ c->parent = nf->src_clk;
+out:
+ return rc;
+}
+
+
struct clk_ops clk_ops_empty;
struct clk_ops clk_ops_rcg = {
@@ -644,6 +786,32 @@
.get_parent = rcg_mnd_clk_get_parent,
};
+struct clk_ops clk_ops_pixel = {
+ .enable = rcg_clk_prepare,
+ .set_rate = set_rate_pixel,
+ .list_rate = rcg_clk_list_rate,
+ .round_rate = rcg_clk_round_rate,
+ .handoff = pixel_rcg_handoff,
+};
+
+struct clk_ops clk_ops_byte = {
+ .enable = rcg_clk_prepare,
+ .set_rate = set_rate_byte,
+ .list_rate = rcg_clk_list_rate,
+ .round_rate = rcg_clk_round_rate,
+ .handoff = byte_rcg_handoff,
+};
+
+struct clk_ops clk_ops_rcg_hdmi = {
+ .enable = rcg_clk_prepare,
+ .set_rate = rcg_clk_set_rate_hdmi,
+ .set_rate = rcg_clk_set_rate,
+ .list_rate = rcg_clk_list_rate,
+ .round_rate = rcg_clk_round_rate,
+ .handoff = rcg_clk_handoff,
+ .get_parent = rcg_clk_get_parent,
+};
+
struct clk_ops clk_ops_branch = {
.enable = branch_clk_enable,
.disable = branch_clk_disable,
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
index 2e1b8a9..7ac7bd3 100644
--- a/arch/arm/mach-msm/clock-local2.h
+++ b/arch/arm/mach-msm/clock-local2.h
@@ -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
@@ -173,6 +173,9 @@
extern struct clk_ops clk_ops_rcg_mnd;
extern struct clk_ops clk_ops_branch;
extern struct clk_ops clk_ops_vote;
+extern struct clk_ops clk_ops_rcg_hdmi;
+extern struct clk_ops clk_ops_byte;
+extern struct clk_ops clk_ops_pixel;
/*
* Clock definition macros
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index c6e93de..c5c4988 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -96,6 +96,8 @@
* @list: List head to link all iommus together
* @clk_reg_virt: Optional clock register virtual address.
* @halt_enabled: Set to 1 if IOMMU halt is supported in the IOMMU, 0 otherwise.
+ * @asid: List of ASID and their usage count (index is ASID value).
+ * @ctx_attach_count: Count of how many context are attached.
*
* A msm_iommu_drvdata holds the global driver data about a single piece
* of an IOMMU hardware instance.
@@ -117,6 +119,8 @@
struct list_head list;
void __iomem *clk_reg_virt;
int halt_enabled;
+ int *asid;
+ unsigned int ctx_attach_count;
};
void msm_iommu_add_drv(struct msm_iommu_drvdata *drv);
diff --git a/arch/arm/mach-msm/include/mach/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index f2a4427..2010abb 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.h
@@ -355,36 +355,6 @@
};
/**
- * enum ipa_rm_resource_name - IPA RM clients identification names
- *
- * Add new mapping to ipa_rm_dep_prod_index() / ipa_rm_dep_cons_index()
- * when adding new entry to this enum.
- */
-enum ipa_rm_resource_name {
- IPA_RM_RESOURCE_PROD = 0,
- IPA_RM_RESOURCE_BRIDGE_PROD = IPA_RM_RESOURCE_PROD,
- IPA_RM_RESOURCE_A2_PROD,
- IPA_RM_RESOURCE_USB_PROD,
- IPA_RM_RESOURCE_HSIC_PROD,
- IPA_RM_RESOURCE_STD_ECM_PROD,
- IPA_RM_RESOURCE_WWAN_0_PROD,
- IPA_RM_RESOURCE_WWAN_1_PROD,
- IPA_RM_RESOURCE_WWAN_2_PROD,
- IPA_RM_RESOURCE_WWAN_3_PROD,
- IPA_RM_RESOURCE_WWAN_4_PROD,
- IPA_RM_RESOURCE_WWAN_5_PROD,
- IPA_RM_RESOURCE_WWAN_6_PROD,
- IPA_RM_RESOURCE_WWAN_7_PROD,
- IPA_RM_RESOURCE_WLAN_PROD,
- IPA_RM_RESOURCE_PROD_MAX,
-
- IPA_RM_RESOURCE_A2_CONS = IPA_RM_RESOURCE_PROD_MAX,
- IPA_RM_RESOURCE_USB_CONS,
- IPA_RM_RESOURCE_HSIC_CONS,
- IPA_RM_RESOURCE_MAX
-};
-
-/**
* enum ipa_rm_event - IPA RM events
*
* Indicate the resource state change
diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h
index cf68108..d3574c8 100644
--- a/arch/arm/mach-msm/include/mach/memory.h
+++ b/arch/arm/mach-msm/include/mach/memory.h
@@ -75,14 +75,9 @@
void clean_and_invalidate_caches(unsigned long, unsigned long, unsigned long);
void clean_caches(unsigned long, unsigned long, unsigned long);
void invalidate_caches(unsigned long, unsigned long, unsigned long);
-int platform_physical_remove_pages(u64, u64);
-int platform_physical_active_pages(u64, u64);
-int platform_physical_low_power_pages(u64, u64);
int msm_get_memory_type_from_name(const char *memtype_name);
unsigned long get_ddr_size(void);
-extern int (*change_memory_power)(u64, u64, int);
-
#if defined(CONFIG_ARCH_MSM_ARM11) || defined(CONFIG_ARCH_MSM_CORTEX_A5)
void write_to_strongly_ordered_memory(void);
void map_page_strongly_ordered(void);
diff --git a/arch/arm/mach-msm/include/mach/msm_memtypes.h b/arch/arm/mach-msm/include/mach/msm_memtypes.h
index a989059..264dad5 100644
--- a/arch/arm/mach-msm/include/mach/msm_memtypes.h
+++ b/arch/arm/mach-msm/include/mach/msm_memtypes.h
@@ -29,7 +29,6 @@
unsigned int get_num_memory_banks(void);
unsigned int get_memory_bank_size(unsigned int);
unsigned int get_memory_bank_start(unsigned int);
-int soc_change_memory_power(u64, u64, int);
enum {
MEMTYPE_NONE = -1,
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index 2748636..a8c7bb7 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -1,7 +1,7 @@
/* linux/include/asm-arm/arch-msm/msm_smd.h
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -141,8 +141,8 @@
* @size: size of the region in bytes
*/
struct smd_smem_regions {
- void *phys_addr;
- unsigned size;
+ phys_addr_t phys_addr;
+ resource_size_t size;
};
struct smd_platform {
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index a7f052e..b3fb8af 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -163,12 +163,6 @@
*/
int usb_bam_client_ready(bool ready);
-/**
- * Returns QDSS BAM connection number
- *
- */
-u8 usb_bam_get_qdss_num(void);
-
#else
static inline int usb_bam_connect(u8 idx, u32 *src_pipe_idx, u32 *dst_pipe_idx)
{
@@ -222,10 +216,5 @@
return -ENODEV;
}
-static inline u8 usb_bam_get_qdss_num(void)
-{
- return -ENODEV;
-}
-
#endif
#endif /* _USB_BAM_H_ */
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index dc0b755..8fe69d9 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -145,6 +145,7 @@
* regulator's callback functions to prevent
* simultaneous updates to the pmic's phase
* voltage.
+ * @apcs_gcc_base virtual address of the APCS GCC registers
*/
struct pmic_gang_vreg {
const char *name;
@@ -156,6 +157,7 @@
int pmic_min_uV_for_retention;
bool retention_enabled;
bool use_phase_switching;
+ void __iomem *apcs_gcc_base;
};
static struct pmic_gang_vreg *the_gang;
@@ -890,12 +892,12 @@
mb();
}
-static void glb_init(struct platform_device *pdev)
+static void glb_init(void __iomem *apcs_gcc_base)
{
/* configure bi-modal switch */
- writel_relaxed(0x0008736E, MSM_APCS_GCC_BASE + PWR_GATE_CONFIG);
+ writel_relaxed(0x0008736E, apcs_gcc_base + PWR_GATE_CONFIG);
/* read kpss version */
- version = readl_relaxed(MSM_APCS_GCC_BASE + VERSION);
+ version = readl_relaxed(apcs_gcc_base + VERSION);
pr_debug("version= 0x%x\n", version);
}
@@ -1117,6 +1119,7 @@
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
struct pmic_gang_vreg *pvreg;
+ struct resource *res;
if (!dev->of_node) {
dev_err(dev, "device tree information missing\n");
@@ -1132,6 +1135,18 @@
return 0;
}
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apcs_gcc");
+ if (!res) {
+ dev_err(&pdev->dev, "missing apcs gcc base addresses\n");
+ return -EINVAL;
+ }
+
+ pvreg->apcs_gcc_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+
+ if (pvreg->apcs_gcc_base == NULL)
+ return -ENOMEM;
+
pvreg->name = "pmic_gang";
pvreg->pmic_vmax_uV = PMIC_VOLTAGE_MIN;
pvreg->pmic_phase_count = -EINVAL;
@@ -1146,7 +1161,7 @@
pr_debug("name=%s inited\n", pvreg->name);
/* global initializtion */
- glb_init(pdev);
+ glb_init(pvreg->apcs_gcc_base);
rc = of_platform_populate(node, NULL, NULL, dev);
if (rc) {
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index 806581d..f3bd34a 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -135,29 +135,6 @@
return (void *)addr;
}
-int (*change_memory_power)(u64, u64, int);
-
-int platform_physical_remove_pages(u64 start, u64 size)
-{
- if (!change_memory_power)
- return 0;
- return change_memory_power(start, size, MEMORY_DEEP_POWERDOWN);
-}
-
-int platform_physical_active_pages(u64 start, u64 size)
-{
- if (!change_memory_power)
- return 0;
- return change_memory_power(start, size, MEMORY_ACTIVE);
-}
-
-int platform_physical_low_power_pages(u64 start, u64 size)
-{
- if (!change_memory_power)
- return 0;
- return change_memory_power(start, size, MEMORY_SELF_REFRESH);
-}
-
char *memtype_name[] = {
"SMI_KERNEL",
"SMI",
diff --git a/arch/arm/mach-msm/memory_topology.c b/arch/arm/mach-msm/memory_topology.c
index 772e63e..781cd69 100644
--- a/arch/arm/mach-msm/memory_topology.c
+++ b/arch/arm/mach-msm/memory_topology.c
@@ -66,136 +66,6 @@
}
#endif
-#if (defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_MSM8930)) \
- && defined(CONFIG_ENABLE_DMM)
-static int rpm_change_memory_state(int retention_mask,
- int active_mask)
-{
- int ret;
- struct msm_rpm_iv_pair cmd[2];
- struct msm_rpm_iv_pair status[2];
-
- cmd[0].id = MSM_RPM_ID_DDR_DMM_0;
- cmd[1].id = MSM_RPM_ID_DDR_DMM_1;
-
- status[0].id = MSM_RPM_STATUS_ID_DDR_DMM_0;
- status[1].id = MSM_RPM_STATUS_ID_DDR_DMM_1;
-
- cmd[0].value = retention_mask;
- cmd[1].value = active_mask;
-
- ret = msm_rpm_set(MSM_RPM_CTX_SET_0, cmd, 2);
- if (ret < 0) {
- pr_err("rpm set failed");
- return -EINVAL;
- }
-
- ret = msm_rpm_get_status(status, 2);
- if (ret < 0) {
- pr_err("rpm status failed");
- return -EINVAL;
- }
- if (status[0].value == retention_mask &&
- status[1].value == active_mask)
- return 0;
- else {
- pr_err("rpm failed to change memory state");
- return -EINVAL;
- }
-}
-
-static int switch_memory_state(int mask, int new_state, int start_region,
- int end_region)
-{
- int final_mask = 0;
- int i;
-
- mutex_lock(&mem_regions_mutex);
-
- for (i = start_region; i <= end_region; i++) {
- if (new_state == mem_regions[i].state)
- goto no_change;
- /* All region states must be the same to change them */
- if (mem_regions[i].state != mem_regions[start_region].state)
- goto no_change;
- }
-
- if (new_state == STATE_POWER_DOWN)
- final_mask = mem_regions_mask & mask;
- else if (new_state == STATE_ACTIVE)
- final_mask = mem_regions_mask | ~mask;
- else
- goto no_change;
-
- pr_info("request memory %d to %d state switch (%d->%d)\n",
- start_region, end_region, mem_regions[start_region].state,
- new_state);
- if (rpm_change_memory_state(final_mask, final_mask) == 0) {
- for (i = start_region; i <= end_region; i++)
- mem_regions[i].state = new_state;
- mem_regions_mask = final_mask;
-
- pr_info("completed memory %d to %d state switch to %d\n",
- start_region, end_region, new_state);
- mutex_unlock(&mem_regions_mutex);
- return 0;
- }
-
- pr_err("failed memory %d to %d state switch (%d->%d)\n",
- start_region, end_region, mem_regions[start_region].state,
- new_state);
-
-no_change:
- mutex_unlock(&mem_regions_mutex);
- return -EINVAL;
-}
-#else
-
-static int switch_memory_state(int mask, int new_state, int start_region,
- int end_region)
-{
- return -EINVAL;
-}
-#endif
-
-/* The hotplug code expects the number of bytes that switched state successfully
- * as the return value, so a return value of zero indicates an error
-*/
-int soc_change_memory_power(u64 start, u64 size, int change)
-{
- int i = 0;
- int mask = default_mask;
- u64 end = start + size;
- int start_region = 0;
- int end_region = 0;
-
- if (change != STATE_ACTIVE && change != STATE_POWER_DOWN) {
- pr_info("requested state transition invalid\n");
- return 0;
- }
- /* Find the memory regions that fall within the range */
- for (i = 0; i < nr_mem_regions; i++) {
- if (mem_regions[i].start <= start &&
- mem_regions[i].start >=
- mem_regions[start_region].start) {
- start_region = i;
- }
- if (end <= mem_regions[i].start + mem_regions[i].size) {
- end_region = i;
- break;
- }
- }
-
- /* Set the bitmask for each region in the range */
- for (i = start_region; i <= end_region; i++)
- mask &= ~(0x1 << i);
-
- if (!switch_memory_state(mask, change, start_region, end_region))
- return size;
- else
- return 0;
-}
-
unsigned int get_num_memory_banks(void)
{
return nr_mem_regions;
diff --git a/arch/arm/mach-msm/qdsp5/audio_ac3.c b/arch/arm/mach-msm/qdsp5/audio_ac3.c
index 0363348..199b322 100644
--- a/arch/arm/mach-msm/qdsp5/audio_ac3.c
+++ b/arch/arm/mach-msm/qdsp5/audio_ac3.c
@@ -1,6 +1,6 @@
/* arch/arm/mach-msm/audio_ac3.c
*
- * Copyright (c) 2008-2009, 2011-2012 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-2013 The Linux Foundation. All rights reserved.
*
* This code also borrows from audio_aac.c, which is
* Copyright (C) 2008 Google, Inc.
@@ -186,8 +186,10 @@
static void audac3_dsp_event(void *private, unsigned id, uint16_t *msg);
static void audac3_config_hostpcm(struct audio *audio);
static void audac3_buffer_refresh(struct audio *audio);
+#ifdef CONFIG_HAS_EARLYSUSPEND
static void audac3_post_event(struct audio *audio, int type,
union msm_audio_event_payload payload);
+#endif
static int rmt_put_resource(struct audio *audio)
{
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 10e40b4..cffb211 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -172,13 +172,13 @@
};
struct smem_area {
- void *phys_addr;
- unsigned size;
+ phys_addr_t phys_addr;
+ resource_size_t size;
void __iomem *virt_addr;
};
static uint32_t num_smem_areas;
static struct smem_area *smem_areas;
-static void *smem_range_check(void *base, unsigned offset);
+static void *smem_range_check(phys_addr_t base, unsigned offset);
struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
@@ -2365,11 +2365,11 @@
* @base: physical base address to check
* @offset: offset from the base to get the final address
*/
-static void *smem_range_check(void *base, unsigned offset)
+static void *smem_range_check(phys_addr_t base, unsigned offset)
{
int i;
- void *phys_addr;
- unsigned size;
+ phys_addr_t phys_addr;
+ resource_size_t size;
for (i = 0; i < num_smem_areas; ++i) {
phys_addr = smem_areas[i].phys_addr;
@@ -2464,7 +2464,7 @@
ret = (void *) (MSM_SHARED_RAM_BASE + toc[id].offset);
else
ret = smem_range_check(
- (void *)(toc[id].reserved & BASE_ADDR_MASK),
+ toc[id].reserved & BASE_ADDR_MASK,
toc[id].offset);
} else {
*size = 0;
@@ -3466,10 +3466,10 @@
(unsigned long)(smem_areas[smem_idx].phys_addr),
smem_areas[smem_idx].size);
if (!smem_areas[smem_idx].virt_addr) {
- pr_err("%s: ioremap_nocache() of addr:%p"
- " size: %x\n", __func__,
- smem_areas[smem_idx].phys_addr,
- smem_areas[smem_idx].size);
+ pr_err("%s: ioremap_nocache() of addr: %pa size: %pa\n",
+ __func__,
+ &smem_areas[smem_idx].phys_addr,
+ &smem_areas[smem_idx].size);
err_ret = -ENOMEM;
++smem_idx;
goto smem_failed;
@@ -3712,8 +3712,8 @@
char *key;
struct resource *r;
void *irq_out_base;
- void *aux_mem_base;
- uint32_t aux_mem_size;
+ phys_addr_t aux_mem_base;
+ resource_size_t aux_mem_size;
int temp_string_size = 11; /* max 3 digit count */
char temp_string[temp_string_size];
int count;
@@ -3721,6 +3721,7 @@
int ret;
const char *compatible;
int subnode_num = 0;
+ resource_size_t irq_out_size;
disable_smsm_reset_handshake = 1;
@@ -3730,7 +3731,13 @@
pr_err("%s: missing '%s'\n", __func__, key);
return -ENODEV;
}
- irq_out_base = (void *)(r->start);
+ irq_out_size = resource_size(r);
+ irq_out_base = ioremap_nocache(r->start, irq_out_size);
+ if (!irq_out_base) {
+ pr_err("%s: ioremap_nocache() of irq_out_base addr:%pr size:%pr\n",
+ __func__, &r->start, &irq_out_size);
+ return -ENOMEM;
+ }
SMD_DBG("%s: %s = %p", __func__, key, irq_out_base);
count = 1;
@@ -3766,20 +3773,20 @@
temp_string);
if (!r)
break;
- aux_mem_base = (void *)(r->start);
- aux_mem_size = (uint32_t)(resource_size(r));
- SMD_DBG("%s: %s = %p %x", __func__, temp_string,
- aux_mem_base, aux_mem_size);
+ aux_mem_base = r->start;
+ aux_mem_size = resource_size(r);
+ SMD_DBG("%s: %s = %pa %pa", __func__, temp_string,
+ &aux_mem_base, &aux_mem_size);
smem_areas[count - 1].phys_addr = aux_mem_base;
smem_areas[count - 1].size = aux_mem_size;
smem_areas[count - 1].virt_addr = ioremap_nocache(
(unsigned long)(smem_areas[count-1].phys_addr),
smem_areas[count - 1].size);
if (!smem_areas[count - 1].virt_addr) {
- pr_err("%s: ioremap_nocache() of addr:%p size: %x\n",
+ pr_err("%s: ioremap_nocache() of addr:%pa size: %pa\n",
__func__,
- smem_areas[count - 1].phys_addr,
- smem_areas[count - 1].size);
+ &smem_areas[count - 1].phys_addr,
+ &smem_areas[count - 1].size);
ret = -ENOMEM;
goto free_smem_areas;
}
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 97e1c17..c8e2dd3 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -1,4 +1,4 @@
-/* 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
@@ -36,6 +36,7 @@
struct msm_spm_driver_data reg_data;
struct msm_spm_power_modes *modes;
uint32_t num_modes;
+ uint32_t cpu_vdd;
};
struct msm_spm_vdd_info {
@@ -54,6 +55,7 @@
struct msm_spm_vdd_info *info = (struct msm_spm_vdd_info *)data;
dev = &per_cpu(msm_cpu_spm_device, info->cpu);
+ dev->cpu_vdd = info->vlevel;
info->err = msm_spm_drv_set_vdd(&dev->reg_data, info->vlevel);
}
@@ -106,7 +108,7 @@
struct msm_spm_device *dev;
dev = &per_cpu(msm_cpu_spm_device, cpu);
- return msm_spm_drv_get_sts_curr_pmic_data(&dev->reg_data);
+ return dev->cpu_vdd;
}
EXPORT_SYMBOL(msm_spm_get_vdd);
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index bf59a9d..38da432 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -721,9 +721,6 @@
extern u32 dtcm_end;
extern u32 itcm_end;
#endif
-#ifdef CONFIG_FIX_MOVABLE_ZONE
- struct zone *zone;
-#endif
max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;
@@ -769,14 +766,6 @@
#endif
}
-#ifdef CONFIG_FIX_MOVABLE_ZONE
- for_each_zone(zone) {
- if (zone_idx(zone) == ZONE_MOVABLE)
- total_unmovable_pages = totalram_pages -
- zone->spanned_pages;
- }
-#endif
-
/*
* Since our memory may not be contiguous, calculate the
* real number of pages we have in this system
@@ -898,39 +887,9 @@
__phys_to_pfn(__pa(__init_end)),
"init");
totalram_pages += reclaimed_initmem;
-#ifdef CONFIG_FIX_MOVABLE_ZONE
- total_unmovable_pages += reclaimed_initmem;
-#endif
}
}
-#ifdef CONFIG_MEMORY_HOTPLUG
-int arch_add_memory(int nid, u64 start, u64 size)
-{
- struct pglist_data *pgdata = NODE_DATA(nid);
- struct zone *zone = pgdata->node_zones + ZONE_MOVABLE;
- unsigned long start_pfn = start >> PAGE_SHIFT;
- unsigned long nr_pages = size >> PAGE_SHIFT;
-
- return __add_pages(nid, zone, start_pfn, nr_pages);
-}
-
-int arch_physical_active_memory(u64 start, u64 size)
-{
- return platform_physical_active_pages(start, size);
-}
-
-int arch_physical_remove_memory(u64 start, u64 size)
-{
- return platform_physical_remove_pages(start, size);
-}
-
-int arch_physical_low_power_memory(u64 start, u64 size)
-{
- return platform_physical_low_power_pages(start, size);
-}
-#endif
-
#ifdef CONFIG_BLK_DEV_INITRD
static int keep_initrd;
@@ -945,9 +904,6 @@
__phys_to_pfn(__pa(end)),
"initrd");
totalram_pages += reclaimed_initrd_mem;
-#ifdef CONFIG_FIX_MOVABLE_ZONE
- total_unmovable_pages += reclaimed_initrd_mem;
-#endif
}
}
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 25cb67c..0e31910 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -940,10 +940,6 @@
find_memory_hole();
#endif
-#if (defined CONFIG_HIGHMEM) && (defined CONFIG_FIX_MOVABLE_ZONE)
- if (movable_reserved_size && __pa(vmalloc_min) > movable_reserved_start)
- vmalloc_min = __va(movable_reserved_start);
-#endif
for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
struct membank *bank = &meminfo.bank[j];
*bank = meminfo.bank[i];
diff --git a/drivers/bif/Kconfig b/drivers/bif/Kconfig
index 502b92b..d9828c5 100644
--- a/drivers/bif/Kconfig
+++ b/drivers/bif/Kconfig
@@ -10,3 +10,17 @@
host master device and one or more slave devices which are located in
a battery pack or also on the host. Enabling this option allows for
BIF consumer drivers to issue transactions via BIF controller drivers.
+
+if BIF
+config BIF_QPNP
+ depends on SPMI
+ depends on OF_SPMI
+ tristate "Qualcomm QPNP BIF support"
+ help
+ This driver supports the QPNP BSI peripheral found inside of Qualcomm
+ QPNP PMIC devices. The BSI peripheral is able to communicate using
+ the BIF protocol. The QPNP BSI driver hooks into the BIF framework.
+ Enable this option in order to provide support for BIF communication
+ on targets which have BSI PMIC peripherals.
+
+endif
diff --git a/drivers/bif/Makefile b/drivers/bif/Makefile
index 02528c1..7604ca7 100644
--- a/drivers/bif/Makefile
+++ b/drivers/bif/Makefile
@@ -2,3 +2,4 @@
# Makefile for kernel BIF framework.
#
obj-$(CONFIG_BIF) += bif-core.o
+obj-$(CONFIG_BIF_QPNP) += qpnp-bsi.o
diff --git a/drivers/bif/qpnp-bsi.c b/drivers/bif/qpnp-bsi.c
new file mode 100644
index 0000000..5068a21
--- /dev/null
+++ b/drivers/bif/qpnp-bsi.c
@@ -0,0 +1,1765 @@
+/* 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/atomic.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/spmi.h>
+#include <linux/workqueue.h>
+#include <linux/bif/driver.h>
+#include <linux/qpnp/qpnp-adc.h>
+
+enum qpnp_bsi_irq {
+ QPNP_BSI_IRQ_ERR,
+ QPNP_BSI_IRQ_RX,
+ QPNP_BSI_IRQ_TX,
+ QPNP_BSI_IRQ_COUNT,
+};
+
+enum qpnp_bsi_com_mode {
+ QPNP_BSI_COM_MODE_IRQ,
+ QPNP_BSI_COM_MODE_POLL,
+};
+
+struct qpnp_bsi_chip {
+ struct bif_ctrl_desc bdesc;
+ struct spmi_device *spmi_dev;
+ struct bif_ctrl_dev *bdev;
+ struct work_struct slave_irq_work;
+ u16 base_addr;
+ u16 batt_id_stat_addr;
+ int r_pullup_ohm;
+ int vid_ref_uV;
+ int tau_index;
+ int tau_sampling_mask;
+ enum bif_bus_state state;
+ enum qpnp_bsi_com_mode com_mode;
+ int irq[QPNP_BSI_IRQ_COUNT];
+ atomic_t irq_flag[QPNP_BSI_IRQ_COUNT];
+ int batt_present_irq;
+ enum qpnp_vadc_channels batt_id_adc_channel;
+};
+
+#define QPNP_BSI_DRIVER_NAME "qcom,qpnp-bsi"
+
+enum qpnp_bsi_registers {
+ QPNP_BSI_REG_TYPE = 0x04,
+ QPNP_BSI_REG_SUBTYPE = 0x05,
+ QPNP_BSI_REG_STATUS = 0x08,
+ QPNP_BSI_REG_ENABLE = 0x46,
+ QPNP_BSI_REG_CLEAR_ERROR = 0x4F,
+ QPNP_BSI_REG_FORCE_BCL_LOW = 0x51,
+ QPNP_BSI_REG_TAU_CONFIG = 0x52,
+ QPNP_BSI_REG_MODE = 0x53,
+ QPNP_BSI_REG_RX_TX_ENABLE = 0x54,
+ QPNP_BSI_REG_TX_DATA_LOW = 0x5A,
+ QPNP_BSI_REG_TX_DATA_HIGH = 0x5B,
+ QPNP_BSI_REG_TX_CTRL = 0x5D,
+ QPNP_BSI_REG_RX_DATA_LOW = 0x60,
+ QPNP_BSI_REG_RX_DATA_HIGH = 0x61,
+ QPNP_BSI_REG_RX_SOURCE = 0x62,
+ QPNP_BSI_REG_BSI_ERROR = 0x70,
+};
+
+#define QPNP_BSI_TYPE 0x02
+#define QPNP_BSI_SUBTYPE 0x10
+
+#define QPNP_BSI_STATUS_ERROR 0x10
+#define QPNP_BSI_STATUS_TX_BUSY 0x08
+#define QPNP_BSI_STATUS_RX_BUSY 0x04
+#define QPNP_BSI_STATUS_TX_GO_BUSY 0x02
+#define QPNP_BSI_STATUS_RX_DATA_READY 0x01
+
+#define QPNP_BSI_ENABLE_MASK 0x80
+#define QPNP_BSI_ENABLE 0x80
+#define QPNP_BSI_DISABLE 0x00
+
+#define QPNP_BSI_TAU_CONFIG_SAMPLE_MASK 0x10
+#define QPNP_BSI_TAU_CONFIG_SAMPLE_8X 0x10
+#define QPNP_BSI_TAU_CONFIG_SAMPLE_4X 0x00
+#define QPNP_BSI_TAU_CONFIG_SPEED_MASK 0x07
+
+#define QPNP_BSI_MODE_TX_PULSE_MASK 0x10
+#define QPNP_BSI_MODE_TX_PULSE_INT 0x10
+#define QPNP_BSI_MODE_TX_PULSE_DATA 0x00
+#define QPNP_BSI_MODE_RX_PULSE_MASK 0x08
+#define QPNP_BSI_MODE_RX_PULSE_INT 0x08
+#define QPNP_BSI_MODE_RX_PULSE_DATA 0x00
+#define QPNP_BSI_MODE_TX_PULSE_T_MASK 0x04
+#define QPNP_BSI_MODE_TX_PULSE_T_WAKE 0x04
+#define QPNP_BSI_MODE_TX_PULSE_T_1_TAU 0x00
+#define QPNP_BSI_MODE_RX_FORMAT_MASK 0x02
+#define QPNP_BSI_MODE_RX_FORMAT_17_BIT 0x02
+#define QPNP_BSI_MODE_RX_FORMAT_11_BIT 0x00
+#define QPNP_BSI_MODE_TX_FORMAT_MASK 0x01
+#define QPNP_BSI_MODE_TX_FORMAT_17_BIT 0x01
+#define QPNP_BSI_MODE_TX_FORMAT_11_BIT 0x00
+
+#define QPNP_BSI_TX_ENABLE_MASK 0x80
+#define QPNP_BSI_TX_ENABLE 0x80
+#define QPNP_BSI_TX_DISABLE 0x00
+#define QPNP_BSI_RX_ENABLE_MASK 0x40
+#define QPNP_BSI_RX_ENABLE 0x40
+#define QPNP_BSI_RX_DISABLE 0x00
+
+#define QPNP_BSI_TX_DATA_HIGH_MASK 0x07
+
+#define QPNP_BSI_TX_CTRL_GO 0x01
+
+#define QPNP_BSI_RX_DATA_HIGH_MASK 0x07
+
+#define QPNP_BSI_RX_SRC_LOOPBACK_FLAG 0x10
+
+#define QPNP_BSI_BSI_ERROR_CLEAR 0x80
+
+#define QPNP_SMBB_BAT_IF_BATT_PRES_MASK 0x80
+#define QPNP_SMBB_BAT_IF_BATT_ID_MASK 0x01
+
+#define QPNP_BSI_NUM_CLOCK_PERIODS 8
+
+struct qpnp_bsi_tau {
+ int period_4x_ns[QPNP_BSI_NUM_CLOCK_PERIODS];
+ int period_8x_ns[QPNP_BSI_NUM_CLOCK_PERIODS];
+ int period_4x_us[QPNP_BSI_NUM_CLOCK_PERIODS];
+ int period_8x_us[QPNP_BSI_NUM_CLOCK_PERIODS];
+};
+
+/* Tau BIF clock periods in ns supported by BSI for either 4x or 8x sampling. */
+static const struct qpnp_bsi_tau qpnp_bsi_tau_period = {
+ .period_4x_ns = {
+ 150420, 122080, 61040, 31670, 15830, 7920, 3960, 2080
+ },
+ .period_8x_ns = {
+ 150420, 122080, 63330, 31670, 15830, 7920, 4170, 2080
+ },
+ .period_4x_us = {
+ 151, 122, 61, 32, 16, 8, 4, 2
+ },
+ .period_8x_us = {
+ 151, 122, 64, 32, 16, 8, 4, 2
+ },
+
+};
+#define QPNP_BSI_MIN_CLOCK_SPEED_NS 2080
+#define QPNP_BSI_MAX_CLOCK_SPEED_NS 150420
+
+#define QPNP_BSI_MIN_PULLUP_OHM 1000
+#define QPNP_BSI_MAX_PULLUP_OHM 500000
+#define QPNP_BSI_DEFAULT_PULLUP_OHM 100000
+#define QPNP_BSI_MIN_VID_REF_UV 500000
+#define QPNP_BSI_MAX_VID_REF_UV 5000000
+#define QPNP_BSI_DEFAULT_VID_REF_UV 1800000
+
+/* These have units of tau_bif. */
+#define QPNP_BSI_MAX_TRANSMIT_CYCLES 36
+#define QPNP_BSI_MIN_RECEIVE_CYCLES 24
+#define QPNP_BSI_MAX_BUS_QUERY_CYCLES 17
+
+/*
+ * Maximum time in microseconds for a slave to transition from suspend to active
+ * state.
+ */
+#define QPNP_BSI_MAX_SLAVE_ACTIVIATION_DELAY_US 50
+
+/*
+ * Maximum time in milliseconds for a slave to transition from power down to
+ * active state.
+ */
+#define QPNP_BSI_MAX_SLAVE_POWER_UP_DELAY_MS 10
+
+#define QPNP_BSI_POWER_UP_LOW_DELAY_US 240
+
+/*
+ * Latencies that are used when determining if polling or interrupts should be
+ * used for a given transaction.
+ */
+#define QPNP_BSI_MAX_IRQ_LATENCY_US 170
+#define QPNP_BSI_MAX_BSI_DATA_READ_LATENCY_US 16
+
+static int qpnp_bsi_set_bus_state(struct bif_ctrl_dev *bdev, int state);
+
+static inline int qpnp_bsi_read(struct qpnp_bsi_chip *chip, u16 addr, u8 *buf,
+ int len)
+{
+ int rc;
+
+ rc = spmi_ext_register_readl(chip->spmi_dev->ctrl,
+ chip->spmi_dev->sid, chip->base_addr + addr, buf, len);
+ if (rc)
+ dev_err(&chip->spmi_dev->dev, "%s: spmi_ext_register_readl() failed. sid=%d, addr=%04X, len=%d, rc=%d\n",
+ __func__, chip->spmi_dev->sid, chip->base_addr + addr,
+ len, rc);
+
+ return rc;
+}
+
+static inline int qpnp_bsi_write(struct qpnp_bsi_chip *chip, u16 addr, u8 *buf,
+ int len)
+{
+ int rc;
+
+ rc = spmi_ext_register_writel(chip->spmi_dev->ctrl,
+ chip->spmi_dev->sid, chip->base_addr + addr, buf, len);
+
+ if (rc)
+ dev_err(&chip->spmi_dev->dev, "%s: spmi_ext_register_writel() failed. sid=%d, addr=%04X, len=%d, rc=%d\n",
+ __func__, chip->spmi_dev->sid, chip->base_addr + addr,
+ len, rc);
+
+ return rc;
+}
+
+enum qpnp_bsi_rx_tx_state {
+ QPNP_BSI_RX_TX_STATE_RX_OFF_TX_OFF,
+ QPNP_BSI_RX_TX_STATE_RX_OFF_TX_DATA,
+ QPNP_BSI_RX_TX_STATE_RX_OFF_TX_INT,
+ QPNP_BSI_RX_TX_STATE_RX_INT_TX_DATA,
+ QPNP_BSI_RX_TX_STATE_RX_DATA_TX_DATA,
+ QPNP_BSI_RX_TX_STATE_RX_INT_TX_OFF,
+};
+
+static int qpnp_bsi_rx_tx_config(struct qpnp_bsi_chip *chip,
+ enum qpnp_bsi_rx_tx_state state)
+{
+ u8 buf[2] = {0, 0};
+ int rc;
+
+ buf[0] = QPNP_BSI_MODE_TX_FORMAT_11_BIT
+ | QPNP_BSI_MODE_RX_FORMAT_11_BIT;
+
+ switch (state) {
+ case QPNP_BSI_RX_TX_STATE_RX_OFF_TX_OFF:
+ buf[0] |= QPNP_BSI_MODE_TX_PULSE_DATA |
+ QPNP_BSI_MODE_RX_PULSE_DATA;
+ buf[1] = QPNP_BSI_TX_DISABLE | QPNP_BSI_RX_DISABLE;
+ break;
+ case QPNP_BSI_RX_TX_STATE_RX_OFF_TX_DATA:
+ buf[0] |= QPNP_BSI_MODE_TX_PULSE_DATA |
+ QPNP_BSI_MODE_RX_PULSE_DATA;
+ buf[1] = QPNP_BSI_TX_ENABLE | QPNP_BSI_RX_DISABLE;
+ break;
+ case QPNP_BSI_RX_TX_STATE_RX_OFF_TX_INT:
+ buf[0] |= QPNP_BSI_MODE_TX_PULSE_INT |
+ QPNP_BSI_MODE_RX_PULSE_DATA;
+ buf[1] = QPNP_BSI_TX_ENABLE | QPNP_BSI_RX_DISABLE;
+ break;
+ case QPNP_BSI_RX_TX_STATE_RX_INT_TX_DATA:
+ buf[0] |= QPNP_BSI_MODE_TX_PULSE_DATA |
+ QPNP_BSI_MODE_RX_PULSE_INT;
+ buf[1] = QPNP_BSI_TX_ENABLE | QPNP_BSI_RX_ENABLE;
+ break;
+ case QPNP_BSI_RX_TX_STATE_RX_DATA_TX_DATA:
+ buf[0] |= QPNP_BSI_MODE_TX_PULSE_DATA |
+ QPNP_BSI_MODE_RX_PULSE_DATA;
+ buf[1] = QPNP_BSI_TX_ENABLE | QPNP_BSI_RX_ENABLE;
+ break;
+ case QPNP_BSI_RX_TX_STATE_RX_INT_TX_OFF:
+ buf[0] |= QPNP_BSI_MODE_TX_PULSE_DATA |
+ QPNP_BSI_MODE_RX_PULSE_INT;
+ buf[1] = QPNP_BSI_TX_DISABLE | QPNP_BSI_RX_DISABLE;
+ break;
+ default:
+ dev_err(&chip->spmi_dev->dev, "%s: invalid state=%d\n",
+ __func__, state);
+ return -EINVAL;
+ }
+
+ rc = qpnp_bsi_write(chip, QPNP_BSI_REG_MODE, buf, 2);
+ if (rc)
+ dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+ __func__, rc);
+
+ return rc;
+}
+
+static void qpnp_bsi_slave_irq_work(struct work_struct *work)
+{
+ struct qpnp_bsi_chip *chip
+ = container_of(work, struct qpnp_bsi_chip, slave_irq_work);
+ int rc;
+
+ rc = bif_ctrl_notify_slave_irq(chip->bdev);
+ if (rc)
+ pr_err("Could not notify BIF core about slave interrupt, rc=%d\n",
+ rc);
+}
+
+static irqreturn_t qpnp_bsi_isr(int irq, void *data)
+{
+ struct qpnp_bsi_chip *chip = data;
+ bool found = false;
+ int i;
+
+ for (i = 0; i < QPNP_BSI_IRQ_COUNT; i++) {
+ if (irq == chip->irq[i]) {
+ found = true;
+ atomic_cmpxchg(&chip->irq_flag[i], 0, 1);
+
+ /* Check if this is a slave interrupt. */
+ if (i == QPNP_BSI_IRQ_RX
+ && chip->state == BIF_BUS_STATE_INTERRUPT) {
+ /* Slave IRQ makes the bus active. */
+ qpnp_bsi_rx_tx_config(chip,
+ QPNP_BSI_RX_TX_STATE_RX_OFF_TX_OFF);
+ chip->state = BIF_BUS_STATE_ACTIVE;
+ schedule_work(&chip->slave_irq_work);
+ }
+ }
+ }
+
+ if (!found)
+ pr_err("Unknown interrupt: %d\n", irq);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t qpnp_bsi_batt_present_isr(int irq, void *data)
+{
+ struct qpnp_bsi_chip *chip = data;
+ int rc;
+
+ if (!chip->bdev)
+ return IRQ_HANDLED;
+
+ rc = bif_ctrl_notify_battery_changed(chip->bdev);
+ if (rc)
+ pr_err("Could not notify about battery state change, rc=%d\n",
+ rc);
+
+ return IRQ_HANDLED;
+}
+
+static void qpnp_bsi_set_com_mode(struct qpnp_bsi_chip *chip,
+ enum qpnp_bsi_com_mode mode)
+{
+ int i;
+
+ if (chip->com_mode == mode)
+ return;
+
+ if (mode == QPNP_BSI_COM_MODE_IRQ)
+ for (i = 0; i < QPNP_BSI_IRQ_COUNT; i++)
+ enable_irq(chip->irq[i]);
+ else
+ for (i = 0; i < QPNP_BSI_IRQ_COUNT; i++)
+ disable_irq(chip->irq[i]);
+
+ chip->com_mode = mode;
+}
+
+static inline bool qpnp_bsi_check_irq(struct qpnp_bsi_chip *chip, int irq)
+{
+ return atomic_cmpxchg(&chip->irq_flag[irq], 1, 0);
+}
+
+static void qpnp_bsi_clear_irq_flags(struct qpnp_bsi_chip *chip)
+{
+ int i;
+
+ for (i = 0; i < QPNP_BSI_IRQ_COUNT; i++)
+ atomic_set(&chip->irq_flag[i], 0);
+}
+
+static inline int qpnp_bsi_get_tau_ns(struct qpnp_bsi_chip *chip)
+{
+ if (chip->tau_sampling_mask == QPNP_BSI_TAU_CONFIG_SAMPLE_4X)
+ return qpnp_bsi_tau_period.period_4x_ns[chip->tau_index];
+ else
+ return qpnp_bsi_tau_period.period_8x_ns[chip->tau_index];
+}
+
+static inline int qpnp_bsi_get_tau_us(struct qpnp_bsi_chip *chip)
+{
+ if (chip->tau_sampling_mask == QPNP_BSI_TAU_CONFIG_SAMPLE_4X)
+ return qpnp_bsi_tau_period.period_4x_us[chip->tau_index];
+ else
+ return qpnp_bsi_tau_period.period_8x_us[chip->tau_index];
+}
+
+/* Checks if BSI is in an error state and clears the error if it is. */
+static int qpnp_bsi_clear_bsi_error(struct qpnp_bsi_chip *chip)
+{
+ int rc, delay_us;
+ u8 reg;
+
+ rc = qpnp_bsi_read(chip, QPNP_BSI_REG_BSI_ERROR, ®, 1);
+ if (rc) {
+ dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_read() failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ if (reg > 0) {
+ /*
+ * Delay before clearing the BSI error in case a transaction is
+ * still in flight.
+ */
+ delay_us = QPNP_BSI_MAX_TRANSMIT_CYCLES
+ * qpnp_bsi_get_tau_us(chip);
+ udelay(delay_us);
+
+ pr_info("PMIC BSI module in error state, error=%d\n", reg);
+
+ reg = QPNP_BSI_BSI_ERROR_CLEAR;
+ rc = qpnp_bsi_write(chip, QPNP_BSI_REG_CLEAR_ERROR, ®, 1);
+ if (rc)
+ dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+ __func__, rc);
+ }
+
+ return rc;
+}
+
+static int qpnp_bsi_get_bsi_error(struct qpnp_bsi_chip *chip)
+{
+ int rc;
+ u8 reg;
+
+ rc = qpnp_bsi_read(chip, QPNP_BSI_REG_BSI_ERROR, ®, 1);
+ if (rc) {
+ dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_read() failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ return reg;
+}
+
+static int qpnp_bsi_wait_for_tx(struct qpnp_bsi_chip *chip, int timeout)
+{
+ int rc = 0;
+
+ /* Wait for TX or ERR IRQ. */
+ while (timeout > 0) {
+ if (qpnp_bsi_check_irq(chip, QPNP_BSI_IRQ_ERR)) {
+ dev_err(&chip->spmi_dev->dev, "%s: transaction error occurred, BSI error=%d\n",
+ __func__, qpnp_bsi_get_bsi_error(chip));
+ return -EIO;
+ }
+
+ if (qpnp_bsi_check_irq(chip, QPNP_BSI_IRQ_TX))
+ break;
+
+ udelay(1);
+ timeout--;
+ }
+
+ if (timeout == 0) {
+ rc = -ETIMEDOUT;
+ dev_err(&chip->spmi_dev->dev, "%s: transaction timed out, no interrupts received, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ return rc;
+}
+
+static int qpnp_bsi_issue_transaction(struct qpnp_bsi_chip *chip,
+ int transaction, u8 data)
+{
+ int rc;
+ u8 buf[4];
+
+ /* MIPI_BIF_DATA_TX_0 = BIF word bits 7 to 0 */
+ buf[0] = data;
+ /* MIPI_BIF_DATA_TX_1 = BIF word BCF, bits 9 to 8 */
+ buf[1] = transaction & QPNP_BSI_TX_DATA_HIGH_MASK;
+ /* MIPI_BIF_DATA_TX_2 ignored */
+ buf[2] = 0x00;
+ /* MIPI_BIF_TX_CTL bit 0 written to start the transaction. */
+ buf[3] = QPNP_BSI_TX_CTRL_GO;
+
+ /* Write the TX_DATA bytes and initiate the transaction. */
+ rc = qpnp_bsi_write(chip, QPNP_BSI_REG_TX_DATA_LOW, buf, 4);
+ if (rc)
+ dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+}
+
+static int qpnp_bsi_issue_transaction_wait_for_tx(struct qpnp_bsi_chip *chip,
+ int transaction, u8 data)
+{
+ int rc, timeout;
+
+ rc = qpnp_bsi_issue_transaction(chip, transaction, data);
+ if (rc)
+ return rc;
+
+ timeout = QPNP_BSI_MAX_TRANSMIT_CYCLES * qpnp_bsi_get_tau_us(chip)
+ + QPNP_BSI_MAX_IRQ_LATENCY_US;
+
+ rc = qpnp_bsi_wait_for_tx(chip, timeout);
+
+ return rc;
+}
+
+static int qpnp_bsi_wait_for_rx(struct qpnp_bsi_chip *chip, int timeout)
+{
+ int rc = 0;
+
+ /* Wait for RX IRQ to indicate that data is ready to read. */
+ while (timeout > 0) {
+ if (qpnp_bsi_check_irq(chip, QPNP_BSI_IRQ_ERR)) {
+ dev_err(&chip->spmi_dev->dev, "%s: transaction error occurred, BSI error=%d\n",
+ __func__, qpnp_bsi_get_bsi_error(chip));
+ return -EIO;
+ }
+
+ if (qpnp_bsi_check_irq(chip, QPNP_BSI_IRQ_RX))
+ break;
+
+ udelay(1);
+ timeout--;
+ }
+
+ if (timeout == 0)
+ rc = -ETIMEDOUT;
+
+ return rc;
+}
+
+static int qpnp_bsi_bus_transaction(struct bif_ctrl_dev *bdev, int transaction,
+ u8 data)
+{
+ struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+ int rc;
+
+ rc = qpnp_bsi_clear_bsi_error(chip);
+ if (rc)
+ return rc;
+
+ qpnp_bsi_clear_irq_flags(chip);
+
+ qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_IRQ);
+
+ rc = qpnp_bsi_set_bus_state(bdev, BIF_BUS_STATE_ACTIVE);
+ if (rc) {
+ dev_err(&chip->spmi_dev->dev, "%s: failed to set bus state, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_OFF_TX_DATA);
+ if (rc)
+ return rc;
+
+ rc = qpnp_bsi_issue_transaction_wait_for_tx(chip, transaction, data);
+ if (rc)
+ return rc;
+
+ rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_OFF_TX_OFF);
+
+ return rc;
+}
+
+static int qpnp_bsi_bus_transaction_query(struct bif_ctrl_dev *bdev,
+ int transaction, u8 data, bool *query_response)
+{
+ struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+ int rc, timeout;
+
+ rc = qpnp_bsi_clear_bsi_error(chip);
+ if (rc)
+ return rc;
+
+ qpnp_bsi_clear_irq_flags(chip);
+
+ qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_IRQ);
+
+ rc = qpnp_bsi_set_bus_state(bdev, BIF_BUS_STATE_ACTIVE);
+ if (rc) {
+ dev_err(&chip->spmi_dev->dev, "%s: failed to set bus state, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_INT_TX_DATA);
+ if (rc)
+ return rc;
+
+ rc = qpnp_bsi_issue_transaction_wait_for_tx(chip, transaction, data);
+ if (rc)
+ return rc;
+
+ timeout = QPNP_BSI_MAX_BUS_QUERY_CYCLES * qpnp_bsi_get_tau_us(chip)
+ + QPNP_BSI_MAX_IRQ_LATENCY_US;
+
+ rc = qpnp_bsi_wait_for_rx(chip, timeout);
+ if (rc == 0) {
+ *query_response = true;
+ } else if (rc == -ETIMEDOUT) {
+ *query_response = false;
+ rc = 0;
+ }
+
+ rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_OFF_TX_OFF);
+
+ return rc;
+}
+
+static int qpnp_bsi_bus_transaction_read(struct bif_ctrl_dev *bdev,
+ int transaction, u8 data, int *response)
+{
+ struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+ int rc, timeout;
+ u8 buf[3];
+
+ rc = qpnp_bsi_clear_bsi_error(chip);
+ if (rc)
+ return rc;
+
+ qpnp_bsi_clear_irq_flags(chip);
+
+ qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_IRQ);
+
+ rc = qpnp_bsi_set_bus_state(bdev, BIF_BUS_STATE_ACTIVE);
+ if (rc) {
+ dev_err(&chip->spmi_dev->dev, "%s: failed to set bus state, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_DATA_TX_DATA);
+ if (rc)
+ return rc;
+
+ rc = qpnp_bsi_issue_transaction_wait_for_tx(chip, transaction, data);
+ if (rc)
+ return rc;
+
+ timeout = QPNP_BSI_MAX_TRANSMIT_CYCLES * qpnp_bsi_get_tau_us(chip)
+ + QPNP_BSI_MAX_IRQ_LATENCY_US;
+
+ rc = qpnp_bsi_wait_for_rx(chip, timeout);
+ if (rc) {
+ if (rc == -ETIMEDOUT) {
+ /*
+ * No error message is printed in this case in order
+ * to provide silent operation when checking if a slave
+ * is selected using the transaction query bus command.
+ */
+ dev_dbg(&chip->spmi_dev->dev, "%s: transaction timed out, no interrupts received, rc=%d\n",
+ __func__, rc);
+ }
+ return rc;
+ }
+
+ /* Read the RX_DATA bytes. */
+ rc = qpnp_bsi_read(chip, QPNP_BSI_REG_RX_DATA_LOW, buf, 3);
+ if (rc) {
+ dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_read() failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ if (buf[2] & QPNP_BSI_RX_SRC_LOOPBACK_FLAG) {
+ rc = -EIO;
+ dev_err(&chip->spmi_dev->dev, "%s: unexpected loopback data read, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ *response = ((int)(buf[1] & QPNP_BSI_RX_DATA_HIGH_MASK) << 8) | buf[0];
+
+ rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_OFF_TX_OFF);
+
+ return 0;
+}
+
+/*
+ * Wait for RX_FLOW_STATUS to be set to 1 which indicates that another BIF word
+ * can be read from PMIC registers.
+ */
+static int qpnp_bsi_wait_for_rx_data(struct qpnp_bsi_chip *chip)
+{
+ int rc = 0;
+ int timeout;
+ u8 reg;
+
+ timeout = QPNP_BSI_MAX_TRANSMIT_CYCLES * qpnp_bsi_get_tau_us(chip);
+
+ /* Wait for RX_FLOW_STATUS == 1 or ERR_FLAG == 1. */
+ while (timeout > 0) {
+ rc = qpnp_bsi_read(chip, QPNP_BSI_REG_STATUS, ®, 1);
+ if (rc) {
+ dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ if (reg & QPNP_BSI_STATUS_ERROR) {
+ dev_err(&chip->spmi_dev->dev, "%s: transaction error occurred, BSI error=%d\n",
+ __func__, qpnp_bsi_get_bsi_error(chip));
+ return -EIO;
+ }
+
+ if (reg & QPNP_BSI_STATUS_RX_DATA_READY) {
+ /* BSI RX has data word latched. */
+ return 0;
+ }
+
+ udelay(1);
+ timeout--;
+ }
+
+ rc = -ETIMEDOUT;
+ dev_err(&chip->spmi_dev->dev, "%s: transaction timed out, RX_FLOW_STATUS never set to 1, rc=%d\n",
+ __func__, rc);
+
+ return rc;
+}
+
+/*
+ * Wait for TX_GO_STATUS to be set to 0 which indicates that another BIF word
+ * can be enqueued.
+ */
+static int qpnp_bsi_wait_for_tx_go(struct qpnp_bsi_chip *chip)
+{
+ int rc = 0;
+ int timeout;
+ u8 reg;
+
+ timeout = QPNP_BSI_MAX_TRANSMIT_CYCLES * qpnp_bsi_get_tau_us(chip);
+
+ /* Wait for TX_GO_STATUS == 0 or ERR_FLAG == 1. */
+ while (timeout > 0) {
+ rc = qpnp_bsi_read(chip, QPNP_BSI_REG_STATUS, ®, 1);
+ if (rc) {
+ dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ if (reg & QPNP_BSI_STATUS_ERROR) {
+ dev_err(&chip->spmi_dev->dev, "%s: transaction error occurred, BSI error=%d\n",
+ __func__, qpnp_bsi_get_bsi_error(chip));
+ return -EIO;
+ }
+
+ if (!(reg & QPNP_BSI_STATUS_TX_GO_BUSY)) {
+ /* BSI TX is ready to accept the next word. */
+ return 0;
+ }
+
+ udelay(1);
+ timeout--;
+ }
+
+ rc = -ETIMEDOUT;
+ dev_err(&chip->spmi_dev->dev, "%s: transaction timed out, TX_GO_STATUS never set to 0, rc=%d\n",
+ __func__, rc);
+
+ return rc;
+}
+
+/*
+ * Wait for TX_BUSY to be set to 0 which indicates that the TX data has been
+ * successfully transmitted.
+ */
+static int qpnp_bsi_wait_for_tx_idle(struct qpnp_bsi_chip *chip)
+{
+ int rc = 0;
+ int timeout;
+ u8 reg;
+
+ timeout = QPNP_BSI_MAX_TRANSMIT_CYCLES * qpnp_bsi_get_tau_us(chip);
+
+ /* Wait for TX_BUSY == 0 or ERR_FLAG == 1. */
+ while (timeout > 0) {
+ rc = qpnp_bsi_read(chip, QPNP_BSI_REG_STATUS, ®, 1);
+ if (rc) {
+ dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ if (reg & QPNP_BSI_STATUS_ERROR) {
+ dev_err(&chip->spmi_dev->dev, "%s: transaction error occurred, BSI error=%d\n",
+ __func__, qpnp_bsi_get_bsi_error(chip));
+ return -EIO;
+ }
+
+ if (!(reg & QPNP_BSI_STATUS_TX_BUSY)) {
+ /* BSI TX is idle. */
+ return 0;
+ }
+
+ udelay(1);
+ timeout--;
+ }
+
+ rc = -ETIMEDOUT;
+ dev_err(&chip->spmi_dev->dev, "%s: transaction timed out, TX_BUSY never set to 0, rc=%d\n",
+ __func__, rc);
+
+ return rc;
+}
+
+/*
+ * For burst read length greater than 1, send necessary RBL and RBE BIF bus
+ * commands.
+ */
+static int qpnp_bsi_send_burst_length(struct qpnp_bsi_chip *chip, int burst_len)
+{
+ int rc = 0;
+
+ /*
+ * Send burst read length bus commands according to the following:
+ *
+ * 256 --> RBL0
+ * 0-255 = 16 * y + x --> RBEy and RBLx
+ * RBE0 does not need to be sent
+ * RBL0 does not need to be sent
+ */
+ if (burst_len == 256) {
+ rc = qpnp_bsi_issue_transaction(chip, BIF_TRANS_BC,
+ BIF_CMD_RBL);
+ if (rc)
+ return rc;
+
+ rc = qpnp_bsi_wait_for_tx_go(chip);
+ if (rc)
+ return rc;
+ } else if (burst_len >= 16) {
+ rc = qpnp_bsi_issue_transaction(chip, BIF_TRANS_BC,
+ BIF_CMD_RBE + (burst_len / 16));
+ if (rc)
+ return rc;
+
+ rc = qpnp_bsi_wait_for_tx_go(chip);
+ if (rc)
+ return rc;
+ }
+
+ if (burst_len % 16) {
+ rc = qpnp_bsi_issue_transaction(chip, BIF_TRANS_BC,
+ BIF_CMD_RBL + (burst_len % 16));
+ if (rc)
+ return rc;
+
+ rc = qpnp_bsi_wait_for_tx_go(chip);
+ if (rc)
+ return rc;
+ }
+
+ return rc;
+}
+
+/* Perform validation steps on received BIF data. */
+static int qpnp_bsi_validate_rx_data(struct qpnp_bsi_chip *chip, int response,
+ u8 rx2_data, bool last_word)
+{
+ int err = -EIO;
+
+ if (rx2_data & QPNP_BSI_RX_SRC_LOOPBACK_FLAG) {
+ dev_err(&chip->spmi_dev->dev, "%s: unexpected loopback data read, rc=%d\n",
+ __func__, err);
+ return err;
+ }
+
+ if (!(response & BIF_SLAVE_RD_ACK)) {
+ dev_err(&chip->spmi_dev->dev, "%s: BIF register read error=0x%02X\n",
+ __func__, response & BIF_SLAVE_RD_ERR);
+ return err;
+ }
+
+ if (last_word && !(response & BIF_SLAVE_RD_EOT)) {
+ dev_err(&chip->spmi_dev->dev, "%s: BIF register read error, last RD packet has EOT=0\n",
+ __func__);
+ return err;
+ } else if (!last_word && (response & BIF_SLAVE_RD_EOT)) {
+ dev_err(&chip->spmi_dev->dev, "%s: BIF register read error, RD packet other than last has EOT=1\n",
+ __func__);
+ return err;
+ }
+
+ return 0;
+}
+
+/* Performs all BIF transactions in order to utilize burst reads. */
+static int qpnp_bsi_read_slave_registers(struct bif_ctrl_dev *bdev, u16 addr,
+ u8 *data, int len)
+{
+ struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+ int response = 0;
+ unsigned long flags;
+ int rc, rc2, i, burst_len;
+ u8 buf[3];
+
+ rc = qpnp_bsi_clear_bsi_error(chip);
+ if (rc)
+ return rc;
+
+ qpnp_bsi_clear_irq_flags(chip);
+
+ qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_POLL);
+
+ rc = qpnp_bsi_set_bus_state(bdev, BIF_BUS_STATE_ACTIVE);
+ if (rc) {
+ dev_err(&chip->spmi_dev->dev, "%s: failed to set bus state, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_DATA_TX_DATA);
+ if (rc)
+ return rc;
+
+ while (len > 0) {
+ burst_len = min(len, 256);
+
+ rc = qpnp_bsi_send_burst_length(chip, burst_len);
+ if (rc)
+ return rc;
+
+ rc = qpnp_bsi_issue_transaction(chip, BIF_TRANS_ERA, addr >> 8);
+ if (rc)
+ return rc;
+
+ rc = qpnp_bsi_wait_for_tx_go(chip);
+ if (rc)
+ return rc;
+
+ /* Perform burst read in atomic context. */
+ local_irq_save(flags);
+
+ rc = qpnp_bsi_issue_transaction(chip, BIF_TRANS_RRA,
+ addr & 0xFF);
+ if (rc)
+ goto burst_err;
+
+ for (i = 0; i < burst_len; i++) {
+ rc = qpnp_bsi_wait_for_rx_data(chip);
+ if (rc)
+ goto burst_err;
+
+ /* Read the RX_DATA bytes. */
+ rc = qpnp_bsi_read(chip, QPNP_BSI_REG_RX_DATA_LOW, buf,
+ 3);
+ if (rc) {
+ dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_read() failed, rc=%d\n",
+ __func__, rc);
+ goto burst_err;
+ }
+
+ response = ((buf[1] & QPNP_BSI_RX_DATA_HIGH_MASK) << 8)
+ | buf[0];
+
+ rc = qpnp_bsi_validate_rx_data(chip, response, buf[2],
+ i == burst_len - 1);
+ if (rc)
+ goto burst_err;
+
+ data[i] = buf[0];
+ }
+ local_irq_restore(flags);
+
+ addr += burst_len;
+ data += burst_len;
+ len -= burst_len;
+ }
+
+ rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_OFF_TX_OFF);
+
+ return rc;
+
+burst_err:
+ local_irq_restore(flags);
+
+ rc2 = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_OFF_TX_OFF);
+ if (rc2 < 0)
+ rc = rc2;
+
+ return rc;
+}
+
+/* Performs all BIF transactions in order to utilize burst writes. */
+static int qpnp_bsi_write_slave_registers(struct bif_ctrl_dev *bdev, u16 addr,
+ const u8 *data, int len)
+{
+ struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+ unsigned long flags;
+ int rc, rc2, i;
+
+ rc = qpnp_bsi_clear_bsi_error(chip);
+ if (rc)
+ return rc;
+
+ qpnp_bsi_clear_irq_flags(chip);
+
+ qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_POLL);
+
+ rc = qpnp_bsi_set_bus_state(bdev, BIF_BUS_STATE_ACTIVE);
+ if (rc) {
+ dev_err(&chip->spmi_dev->dev, "%s: failed to set bus state, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_OFF_TX_DATA);
+ if (rc)
+ return rc;
+
+ rc = qpnp_bsi_issue_transaction(chip, BIF_TRANS_ERA, addr >> 8);
+ if (rc)
+ return rc;
+
+ rc = qpnp_bsi_wait_for_tx_go(chip);
+ if (rc)
+ return rc;
+
+ rc = qpnp_bsi_issue_transaction(chip, BIF_TRANS_WRA, addr & 0xFF);
+ if (rc)
+ return rc;
+
+ rc = qpnp_bsi_wait_for_tx_go(chip);
+ if (rc)
+ return rc;
+
+ /* Perform burst write in atomic context. */
+ local_irq_save(flags);
+
+ for (i = 0; i < len; i++) {
+ rc = qpnp_bsi_issue_transaction(chip, BIF_TRANS_WD, data[i]);
+ if (rc)
+ goto burst_err;
+
+ rc = qpnp_bsi_wait_for_tx_go(chip);
+ if (rc)
+ goto burst_err;
+ }
+
+ rc = qpnp_bsi_wait_for_tx_idle(chip);
+ if (rc)
+ goto burst_err;
+
+ local_irq_restore(flags);
+
+ rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_OFF_TX_OFF);
+
+ return rc;
+
+burst_err:
+ local_irq_restore(flags);
+
+ rc2 = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_OFF_TX_OFF);
+ if (rc2 < 0)
+ rc = rc2;
+
+ return rc;
+}
+
+
+static int qpnp_bsi_bus_set_interrupt_mode(struct bif_ctrl_dev *bdev)
+{
+ struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+ int rc;
+
+ rc = qpnp_bsi_clear_bsi_error(chip);
+ if (rc)
+ return rc;
+
+ qpnp_bsi_clear_irq_flags(chip);
+
+ qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_IRQ);
+
+ /*
+ * Temporarily change the bus to active state so that the EINT command
+ * can be issued.
+ */
+ rc = qpnp_bsi_set_bus_state(bdev, BIF_BUS_STATE_ACTIVE);
+ if (rc) {
+ dev_err(&chip->spmi_dev->dev, "%s: failed to set bus state, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_INT_TX_DATA);
+ if (rc)
+ return rc;
+
+ /*
+ * Set the bus state to interrupt mode so that an RX interrupt which
+ * occurs immediately after issuing the EINT command is handled
+ * properly.
+ */
+ chip->state = BIF_BUS_STATE_INTERRUPT;
+
+ /* Send EINT bus command. */
+ rc = qpnp_bsi_issue_transaction_wait_for_tx(chip, BIF_TRANS_BC,
+ BIF_CMD_EINT);
+ if (rc)
+ return rc;
+
+ rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_INT_TX_OFF);
+
+ return rc;
+}
+
+static int qpnp_bsi_bus_set_active_mode(struct bif_ctrl_dev *bdev,
+ int prev_state)
+{
+ struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+ int rc;
+ u8 buf[2];
+
+ rc = qpnp_bsi_clear_bsi_error(chip);
+ if (rc)
+ return rc;
+
+ buf[0] = QPNP_BSI_MODE_TX_PULSE_INT |
+ QPNP_BSI_MODE_RX_PULSE_DATA;
+ buf[1] = QPNP_BSI_TX_ENABLE | QPNP_BSI_RX_DISABLE;
+
+ if (prev_state == BIF_BUS_STATE_INTERRUPT)
+ buf[0] |= QPNP_BSI_MODE_TX_PULSE_T_1_TAU;
+ else
+ buf[0] |= QPNP_BSI_MODE_TX_PULSE_T_WAKE;
+
+ rc = qpnp_bsi_write(chip, QPNP_BSI_REG_MODE, buf, 2);
+ if (rc) {
+ dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ buf[0] = QPNP_BSI_TX_CTRL_GO;
+ /* Initiate BCL low pulse. */
+ rc = qpnp_bsi_write(chip, QPNP_BSI_REG_TX_CTRL, buf, 1);
+ if (rc) {
+ dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ switch (prev_state) {
+ case BIF_BUS_STATE_INTERRUPT:
+ udelay(qpnp_bsi_get_tau_us(chip) * 4);
+ break;
+ case BIF_BUS_STATE_STANDBY:
+ udelay(qpnp_bsi_get_tau_us(chip)
+ + QPNP_BSI_MAX_SLAVE_ACTIVIATION_DELAY_US
+ + QPNP_BSI_POWER_UP_LOW_DELAY_US);
+ break;
+ case BIF_BUS_STATE_POWER_DOWN:
+ msleep(QPNP_BSI_MAX_SLAVE_POWER_UP_DELAY_MS);
+ break;
+ }
+
+ return rc;
+}
+
+static int qpnp_bsi_get_bus_state(struct bif_ctrl_dev *bdev)
+{
+ struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+
+ return chip->state;
+}
+
+static int qpnp_bsi_set_bus_state(struct bif_ctrl_dev *bdev, int state)
+{
+ struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+ int rc = 0;
+
+ if (state == chip->state)
+ return 0;
+
+ switch (state) {
+ case BIF_BUS_STATE_MASTER_DISABLED:
+ pr_info("master disable not yet supported.\n");
+ break;
+ case BIF_BUS_STATE_POWER_DOWN:
+ rc = qpnp_bsi_bus_transaction(bdev, BIF_TRANS_BC, BIF_CMD_PDWN);
+ if (rc)
+ dev_err(&chip->spmi_dev->dev, "%s: failed to enable power down mode, rc=%d\n",
+ __func__, rc);
+ break;
+ case BIF_BUS_STATE_STANDBY:
+ rc = qpnp_bsi_bus_transaction(bdev, BIF_TRANS_BC, BIF_CMD_STBY);
+ if (rc)
+ dev_err(&chip->spmi_dev->dev, "%s: failed to enable standby mode, rc=%d\n",
+ __func__, rc);
+ break;
+ case BIF_BUS_STATE_ACTIVE:
+ rc = qpnp_bsi_bus_set_active_mode(bdev, chip->state);
+ if (rc)
+ dev_err(&chip->spmi_dev->dev, "%s: failed to enable active mode, rc=%d\n",
+ __func__, rc);
+ break;
+ case BIF_BUS_STATE_INTERRUPT:
+ /*
+ * qpnp_bsi_bus_set_interrupt_mode() internally sets
+ * chip->state = BIF_BUS_STATE_INTERRUPT immediately before
+ * issuing the EINT command.
+ */
+ rc = qpnp_bsi_bus_set_interrupt_mode(bdev);
+ if (rc) {
+ dev_err(&chip->spmi_dev->dev, "%s: failed to enable interrupt mode, rc=%d\n",
+ __func__, rc);
+ } else if (chip->state == BIF_BUS_STATE_ACTIVE) {
+ /*
+ * A slave interrupt was received immediately after
+ * issuing the EINT command. Therefore, stay in active
+ * communication mode.
+ */
+ state = BIF_BUS_STATE_ACTIVE;
+ }
+ break;
+ default:
+ rc = -EINVAL;
+ dev_err(&chip->spmi_dev->dev, "%s: invalid state=%d\n",
+ __func__, state);
+ }
+
+ if (!rc)
+ chip->state = state;
+
+ return rc;
+}
+
+/* Returns the smallest tau_bif that is greater than or equal to period_ns. */
+static int qpnp_bsi_tau_bif_higher(int period_ns, int sample_mask)
+{
+ const int *supported_period_ns =
+ (sample_mask == QPNP_BSI_TAU_CONFIG_SAMPLE_4X ?
+ qpnp_bsi_tau_period.period_4x_ns :
+ qpnp_bsi_tau_period.period_8x_ns);
+ int smallest_tau_bif = INT_MAX;
+ int i;
+
+ for (i = QPNP_BSI_NUM_CLOCK_PERIODS - 1; i >= 0; i--) {
+ if (period_ns <= supported_period_ns[i]) {
+ smallest_tau_bif = supported_period_ns[i];
+ break;
+ }
+ }
+
+ return smallest_tau_bif;
+}
+
+/* Returns the largest tau_bif that is less than or equal to period_ns. */
+static int qpnp_bsi_tau_bif_lower(int period_ns, int sample_mask)
+{
+ const int *supported_period_ns =
+ (sample_mask == QPNP_BSI_TAU_CONFIG_SAMPLE_4X ?
+ qpnp_bsi_tau_period.period_4x_ns :
+ qpnp_bsi_tau_period.period_8x_ns);
+ int largest_tau_bif = 0;
+ int i;
+
+ for (i = 0; i < QPNP_BSI_NUM_CLOCK_PERIODS; i++) {
+ if (period_ns >= supported_period_ns[i]) {
+ largest_tau_bif = supported_period_ns[i];
+ break;
+ }
+ }
+
+ return largest_tau_bif;
+}
+
+/*
+ * Moves period_ns into allowed range and then sets tau bif to the period that
+ * is greater than or equal to period_ns.
+ */
+static int qpnp_bsi_set_tau_bif(struct qpnp_bsi_chip *chip, int period_ns)
+{
+ const int *supported_period_ns =
+ (chip->tau_sampling_mask == QPNP_BSI_TAU_CONFIG_SAMPLE_4X ?
+ qpnp_bsi_tau_period.period_4x_ns :
+ qpnp_bsi_tau_period.period_8x_ns);
+ int idx = 0;
+ int i, rc;
+ u8 reg;
+
+ if (period_ns < chip->bdesc.bus_clock_min_ns)
+ period_ns = chip->bdesc.bus_clock_min_ns;
+ else if (period_ns > chip->bdesc.bus_clock_max_ns)
+ period_ns = chip->bdesc.bus_clock_max_ns;
+
+ for (i = QPNP_BSI_NUM_CLOCK_PERIODS - 1; i >= 0; i--) {
+ if (period_ns <= supported_period_ns[i]) {
+ idx = i;
+ break;
+ }
+ }
+
+ /* Set the tau BIF clock period and sampling rate. */
+ reg = chip->tau_sampling_mask | idx;
+ rc = qpnp_bsi_write(chip, QPNP_BSI_REG_TAU_CONFIG, ®, 1);
+ if (rc) {
+ dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ chip->tau_index = idx;
+
+ return 0;
+}
+
+static int qpnp_bsi_get_bus_period(struct bif_ctrl_dev *bdev)
+{
+ struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+
+ return qpnp_bsi_get_tau_ns(chip);
+}
+
+static int qpnp_bsi_set_bus_period(struct bif_ctrl_dev *bdev, int period_ns)
+{
+ struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+
+ return qpnp_bsi_set_tau_bif(chip, period_ns);
+}
+
+static int qpnp_bsi_get_battery_rid(struct bif_ctrl_dev *bdev)
+{
+ struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+ struct qpnp_vadc_result adc_result;
+ int rid_ohm, vid_uV, rc;
+ s64 temp;
+
+ if (chip->batt_id_adc_channel >= ADC_MAX_NUM) {
+ dev_err(&chip->spmi_dev->dev, "%s: no ADC channel specified for Rid measurement\n",
+ __func__);
+ return -ENXIO;
+ }
+
+ rc = qpnp_vadc_read(chip->batt_id_adc_channel, &adc_result);
+ if (!rc) {
+ vid_uV = adc_result.physical;
+
+ if (chip->vid_ref_uV - vid_uV <= 0) {
+ rid_ohm = INT_MAX;
+ } else {
+ temp = (s64)chip->r_pullup_ohm * (s64)vid_uV;
+ do_div(temp, chip->vid_ref_uV - vid_uV);
+ if (temp > INT_MAX)
+ rid_ohm = INT_MAX;
+ else
+ rid_ohm = temp;
+ }
+ } else {
+ dev_err(&chip->spmi_dev->dev, "%s: qpnp_vadc_read(%d) failed, rc=%d\n",
+ __func__, chip->batt_id_adc_channel, rc);
+ rid_ohm = rc;
+ }
+
+ return rid_ohm;
+}
+
+/*
+ * Returns 1 if a battery pack is present on the BIF bus, 0 if a battery pack
+ * is not present, or errno if detection fails.
+ *
+ * Battery detection is based upon the idle BCL voltage.
+ */
+static int qpnp_bsi_get_battery_presence(struct bif_ctrl_dev *bdev)
+{
+ struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+ u8 reg = 0x00;
+ int rc;
+
+ rc = spmi_ext_register_readl(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
+ chip->batt_id_stat_addr, ®, 1);
+ if (rc) {
+ dev_err(&chip->spmi_dev->dev, "%s: spmi_ext_register_readl() failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ return !!(reg & QPNP_SMBB_BAT_IF_BATT_PRES_MASK);
+}
+
+static struct bif_ctrl_ops qpnp_bsi_ops = {
+ .bus_transaction = qpnp_bsi_bus_transaction,
+ .bus_transaction_query = qpnp_bsi_bus_transaction_query,
+ .bus_transaction_read = qpnp_bsi_bus_transaction_read,
+ .get_bus_state = qpnp_bsi_get_bus_state,
+ .set_bus_state = qpnp_bsi_set_bus_state,
+ .get_bus_period = qpnp_bsi_get_bus_period,
+ .set_bus_period = qpnp_bsi_set_bus_period,
+ .read_slave_registers = qpnp_bsi_read_slave_registers,
+ .write_slave_registers = qpnp_bsi_write_slave_registers,
+ .get_battery_rid = qpnp_bsi_get_battery_rid,
+ .get_battery_presence = qpnp_bsi_get_battery_presence,
+};
+
+/* Load all BSI properties from device tree. */
+static int __devinit qpnp_bsi_parse_dt(struct qpnp_bsi_chip *chip,
+ struct spmi_device *spmi)
+{
+ struct device *dev = &spmi->dev;
+ struct device_node *node = spmi->dev.of_node;
+ struct resource *res;
+ int rc, temp;
+
+ chip->batt_id_adc_channel = ADC_MAX_NUM;
+ rc = of_property_read_u32(node, "qcom,channel-num",
+ &chip->batt_id_adc_channel);
+ if (!rc && (chip->batt_id_adc_channel < 0
+ || chip->batt_id_adc_channel >= ADC_MAX_NUM)) {
+ dev_err(dev, "%s: invalid qcom,channel-num=%d specified\n",
+ __func__, chip->batt_id_adc_channel);
+ return -EINVAL;
+ }
+
+ chip->r_pullup_ohm = QPNP_BSI_DEFAULT_PULLUP_OHM;
+ rc = of_property_read_u32(node, "qcom,pullup-ohms",
+ &chip->r_pullup_ohm);
+ if (!rc && (chip->r_pullup_ohm < QPNP_BSI_MIN_PULLUP_OHM ||
+ chip->r_pullup_ohm > QPNP_BSI_MAX_PULLUP_OHM)) {
+ dev_err(dev, "%s: invalid qcom,pullup-ohms=%d property value\n",
+ __func__, chip->r_pullup_ohm);
+ return -EINVAL;
+ }
+
+ chip->vid_ref_uV = QPNP_BSI_DEFAULT_VID_REF_UV;
+ rc = of_property_read_u32(node, "qcom,vref-microvolts",
+ &chip->vid_ref_uV);
+ if (!rc && (chip->vid_ref_uV < QPNP_BSI_MIN_VID_REF_UV ||
+ chip->vid_ref_uV > QPNP_BSI_MAX_VID_REF_UV)) {
+ dev_err(dev, "%s: invalid qcom,vref-microvolts=%d property value\n",
+ __func__, chip->vid_ref_uV);
+ return -EINVAL;
+ }
+
+ res = spmi_get_resource_byname(spmi, NULL, IORESOURCE_MEM, "bsi-base");
+ if (!res) {
+ dev_err(dev, "%s: node is missing BSI base address\n",
+ __func__);
+ return -EINVAL;
+ }
+ chip->base_addr = res->start;
+
+ res = spmi_get_resource_byname(spmi, NULL, IORESOURCE_MEM,
+ "batt-id-status");
+ if (!res) {
+ dev_err(dev, "%s: node is missing BATT_ID status address\n",
+ __func__);
+ return -EINVAL;
+ }
+ chip->batt_id_stat_addr = res->start;
+
+ chip->bdesc.name = spmi_get_primary_dev_name(spmi);
+ if (!chip->bdesc.name) {
+ dev_err(dev, "%s: label binding undefined for node %s\n",
+ __func__, spmi->dev.of_node->full_name);
+ return -EINVAL;
+ }
+
+ /* Use maximum range by default. */
+ chip->bdesc.bus_clock_min_ns = QPNP_BSI_MIN_CLOCK_SPEED_NS;
+ chip->bdesc.bus_clock_max_ns = QPNP_BSI_MAX_CLOCK_SPEED_NS;
+ chip->tau_sampling_mask = QPNP_BSI_TAU_CONFIG_SAMPLE_4X;
+
+ rc = of_property_read_u32(node, "qcom,sample-rate", &temp);
+ if (rc == 0) {
+ if (temp == 4) {
+ chip->tau_sampling_mask = QPNP_BSI_TAU_CONFIG_SAMPLE_4X;
+ } else if (temp == 8) {
+ chip->tau_sampling_mask = QPNP_BSI_TAU_CONFIG_SAMPLE_8X;
+ } else {
+ dev_err(dev, "%s: invalid qcom,sample-rate=%d. Only values of 4 and 8 are supported.\n",
+ __func__, temp);
+ return -EINVAL;
+ }
+ }
+
+ rc = of_property_read_u32(node, "qcom,min-clock-period", &temp);
+ if (rc == 0)
+ chip->bdesc.bus_clock_min_ns = qpnp_bsi_tau_bif_higher(temp,
+ chip->tau_sampling_mask);
+
+ rc = of_property_read_u32(node, "qcom,max-clock-period", &temp);
+ if (rc == 0)
+ chip->bdesc.bus_clock_max_ns = qpnp_bsi_tau_bif_lower(temp,
+ chip->tau_sampling_mask);
+
+ if (chip->bdesc.bus_clock_min_ns > chip->bdesc.bus_clock_max_ns) {
+ dev_err(dev, "%s: invalid qcom,min/max-clock-period.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ chip->irq[QPNP_BSI_IRQ_ERR] = spmi_get_irq_byname(spmi, NULL, "err");
+ if (chip->irq[QPNP_BSI_IRQ_ERR] < 0) {
+ dev_err(dev, "%s: node is missing err irq\n", __func__);
+ return chip->irq[QPNP_BSI_IRQ_ERR];
+ }
+
+ chip->irq[QPNP_BSI_IRQ_RX] = spmi_get_irq_byname(spmi, NULL, "rx");
+ if (chip->irq[QPNP_BSI_IRQ_RX] < 0) {
+ dev_err(dev, "%s: node is missing rx irq\n", __func__);
+ return chip->irq[QPNP_BSI_IRQ_RX];
+ }
+
+ chip->irq[QPNP_BSI_IRQ_TX] = spmi_get_irq_byname(spmi, NULL, "tx");
+ if (chip->irq[QPNP_BSI_IRQ_TX] < 0) {
+ dev_err(dev, "%s: node is missing tx irq\n", __func__);
+ return chip->irq[QPNP_BSI_IRQ_TX];
+ }
+
+ chip->batt_present_irq = spmi_get_irq_byname(spmi, NULL,
+ "batt-present");
+ if (chip->batt_present_irq < 0) {
+ dev_err(dev, "%s: node is missing batt-present irq\n",
+ __func__);
+ return chip->batt_present_irq;
+ }
+
+ return rc;
+}
+
+/* Request all BSI and battery presence IRQs and set them as wakeable. */
+static int __devinit qpnp_bsi_init_irqs(struct qpnp_bsi_chip *chip,
+ struct device *dev)
+{
+ int rc;
+
+ rc = devm_request_irq(dev, chip->irq[QPNP_BSI_IRQ_ERR],
+ qpnp_bsi_isr, IRQF_TRIGGER_RISING, "bsi-err", chip);
+ if (rc < 0) {
+ dev_err(dev, "%s: request for bsi-err irq %d failed, rc=%d\n",
+ __func__, chip->irq[QPNP_BSI_IRQ_ERR], rc);
+ return rc;
+ }
+
+ rc = irq_set_irq_wake(chip->irq[QPNP_BSI_IRQ_ERR], 1);
+ if (rc < 0) {
+ dev_err(dev, "%s: unable to set bsi-err irq %d as wakeable, rc=%d\n",
+ __func__, chip->irq[QPNP_BSI_IRQ_ERR], rc);
+ return rc;
+ }
+
+ rc = devm_request_irq(dev, chip->irq[QPNP_BSI_IRQ_RX],
+ qpnp_bsi_isr, IRQF_TRIGGER_RISING, "bsi-rx", chip);
+ if (rc < 0) {
+ dev_err(dev, "%s: request for bsi-rx irq %d failed, rc=%d\n",
+ __func__, chip->irq[QPNP_BSI_IRQ_RX], rc);
+ goto set_unwakeable_irq_err;
+ }
+
+ rc = irq_set_irq_wake(chip->irq[QPNP_BSI_IRQ_RX], 1);
+ if (rc < 0) {
+ dev_err(dev, "%s: unable to set bsi-rx irq %d as wakeable, rc=%d\n",
+ __func__, chip->irq[QPNP_BSI_IRQ_RX], rc);
+ goto set_unwakeable_irq_err;
+ }
+
+ rc = devm_request_irq(dev, chip->irq[QPNP_BSI_IRQ_TX],
+ qpnp_bsi_isr, IRQF_TRIGGER_RISING, "bsi-tx", chip);
+ if (rc < 0) {
+ dev_err(dev, "%s: request for bsi-tx irq %d failed, rc=%d\n",
+ __func__, chip->irq[QPNP_BSI_IRQ_TX], rc);
+ goto set_unwakeable_irq_rx;
+ }
+
+ rc = irq_set_irq_wake(chip->irq[QPNP_BSI_IRQ_TX], 1);
+ if (rc < 0) {
+ dev_err(dev, "%s: unable to set bsi-tx irq %d as wakeable, rc=%d\n",
+ __func__, chip->irq[QPNP_BSI_IRQ_TX], rc);
+ goto set_unwakeable_irq_rx;
+ }
+
+ rc = devm_request_threaded_irq(dev, chip->batt_present_irq, NULL,
+ qpnp_bsi_batt_present_isr,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_SHARED
+ | IRQF_ONESHOT,
+ "bsi-batt-present", chip);
+ if (rc < 0) {
+ dev_err(dev, "%s: request for bsi-batt-present irq %d failed, rc=%d\n",
+ __func__, chip->batt_present_irq, rc);
+ goto set_unwakeable_irq_tx;
+ }
+
+ rc = irq_set_irq_wake(chip->batt_present_irq, 1);
+ if (rc < 0) {
+ dev_err(dev, "%s: unable to set bsi-batt-present irq %d as wakeable, rc=%d\n",
+ __func__, chip->batt_present_irq, rc);
+ goto set_unwakeable_irq_tx;
+ }
+
+ return rc;
+
+set_unwakeable_irq_tx:
+ irq_set_irq_wake(chip->irq[QPNP_BSI_IRQ_TX], 0);
+set_unwakeable_irq_rx:
+ irq_set_irq_wake(chip->irq[QPNP_BSI_IRQ_RX], 0);
+set_unwakeable_irq_err:
+ irq_set_irq_wake(chip->irq[QPNP_BSI_IRQ_ERR], 0);
+ return rc;
+}
+
+static void qpnp_bsi_cleanup_irqs(struct qpnp_bsi_chip *chip)
+{
+ irq_set_irq_wake(chip->irq[QPNP_BSI_IRQ_ERR], 0);
+ irq_set_irq_wake(chip->irq[QPNP_BSI_IRQ_RX], 0);
+ irq_set_irq_wake(chip->irq[QPNP_BSI_IRQ_TX], 0);
+ irq_set_irq_wake(chip->batt_present_irq, 0);
+}
+
+static int __devinit qpnp_bsi_probe(struct spmi_device *spmi)
+{
+ struct device *dev = &spmi->dev;
+ struct qpnp_bsi_chip *chip;
+ int rc;
+ u8 type[2], reg;
+
+ if (!spmi->dev.of_node) {
+ dev_err(dev, "%s: device node missing\n", __func__);
+ return -ENODEV;
+ }
+
+ chip = devm_kzalloc(dev, sizeof(struct qpnp_bsi_chip), GFP_KERNEL);
+ if (!chip) {
+ dev_err(dev, "%s: Can't allocate qpnp_bsi\n", __func__);
+ return -ENOMEM;
+ }
+
+ rc = qpnp_bsi_parse_dt(chip, spmi);
+ if (rc) {
+ dev_err(dev, "%s: device tree parsing failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ INIT_WORK(&chip->slave_irq_work, qpnp_bsi_slave_irq_work);
+
+ rc = qpnp_bsi_init_irqs(chip, dev);
+ if (rc) {
+ dev_err(dev, "%s: IRQ initialization failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ chip->spmi_dev = spmi;
+ chip->bdesc.ops = &qpnp_bsi_ops;
+ chip->state = BIF_BUS_STATE_POWER_DOWN;
+ chip->com_mode = QPNP_BSI_COM_MODE_IRQ;
+
+ rc = qpnp_bsi_read(chip, QPNP_BSI_REG_TYPE, type, 2);
+ if (rc) {
+ dev_err(dev, "%s: could not read type register, rc=%d\n",
+ __func__, rc);
+ goto cleanup_irqs;
+ }
+
+ if (type[0] != QPNP_BSI_TYPE || type[1] != QPNP_BSI_SUBTYPE) {
+ dev_err(dev, "%s: BSI peripheral is not present; type=0x%02X, subtype=0x%02X\n",
+ __func__, type[0], type[1]);
+ rc = -ENODEV;
+ goto cleanup_irqs;
+ }
+
+ /* Ensure that ADC channel is available if it was specified. */
+ if (chip->batt_id_adc_channel < ADC_MAX_NUM) {
+ rc = qpnp_vadc_is_ready();
+ if (rc) {
+ /* Probe retry, do not print an error message */
+ goto cleanup_irqs;
+ }
+ }
+
+ rc = qpnp_bsi_set_tau_bif(chip, chip->bdesc.bus_clock_min_ns);
+ if (rc) {
+ dev_err(dev, "%s: qpnp_bsi_set_tau_bif() failed, rc=%d\n",
+ __func__, rc);
+ goto cleanup_irqs;
+ }
+
+ /* Enable the BSI module. */
+ reg = QPNP_BSI_ENABLE;
+ rc = qpnp_bsi_write(chip, QPNP_BSI_REG_ENABLE, ®, 1);
+ if (rc) {
+ dev_err(dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+ __func__, rc);
+ goto cleanup_irqs;
+ }
+
+ chip->bdev = bif_ctrl_register(&chip->bdesc, dev, chip,
+ spmi->dev.of_node);
+ if (IS_ERR(chip->bdev)) {
+ rc = PTR_ERR(chip->bdev);
+ dev_err(dev, "%s: bif_ctrl_register failed, rc=%d\n",
+ __func__, rc);
+ goto cleanup_irqs;
+ }
+
+ dev_set_drvdata(dev, chip);
+
+ return rc;
+
+cleanup_irqs:
+ qpnp_bsi_cleanup_irqs(chip);
+ return rc;
+}
+
+static int __devexit qpnp_bsi_remove(struct spmi_device *spmi)
+{
+ struct qpnp_bsi_chip *chip = dev_get_drvdata(&spmi->dev);
+ dev_set_drvdata(&spmi->dev, NULL);
+
+ if (chip) {
+ bif_ctrl_unregister(chip->bdev);
+ qpnp_bsi_cleanup_irqs(chip);
+ }
+
+ return 0;
+}
+
+static struct of_device_id spmi_match_table[] = {
+ { .compatible = QPNP_BSI_DRIVER_NAME, },
+ {}
+};
+
+static const struct spmi_device_id qpnp_bsi_id[] = {
+ { QPNP_BSI_DRIVER_NAME, 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(spmi, qpnp_bsi_id);
+
+static struct spmi_driver qpnp_bsi_driver = {
+ .driver = {
+ .name = QPNP_BSI_DRIVER_NAME,
+ .of_match_table = spmi_match_table,
+ .owner = THIS_MODULE,
+ },
+ .probe = qpnp_bsi_probe,
+ .remove = __devexit_p(qpnp_bsi_remove),
+ .id_table = qpnp_bsi_id,
+};
+
+static int __init qpnp_bsi_init(void)
+{
+ return spmi_driver_register(&qpnp_bsi_driver);
+}
+
+static void __exit qpnp_bsi_exit(void)
+{
+ spmi_driver_unregister(&qpnp_bsi_driver);
+}
+
+MODULE_DESCRIPTION("QPNP PMIC BSI driver");
+MODULE_LICENSE("GPL v2");
+
+arch_initcall(qpnp_bsi_init);
+module_exit(qpnp_bsi_exit);
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 23dd5a1..1c9f968 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -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
@@ -107,92 +107,102 @@
break;
}
}
- if (index == -1)
+ if (index == -1) {
pr_alert("diag: No matching PID for DCI data\n");
+ return;
+ }
/* Using PID of client process, find client buffer */
- for (i = 0; i < MAX_DCI_CLIENTS; i++) {
- if (driver->dci_client_tbl[i].client != NULL) {
- if (curr_client_pid ==
- driver->dci_client_tbl[i].client->tgid) {
- /* copy pkt rsp in client buf */
- entry = &(driver->dci_client_tbl[i]);
- if (DCI_CHK_CAPACITY(entry, 8+write_len)) {
- pr_alert("diag: create capacity for pkt rsp\n");
- entry->total_capacity += 8+write_len;
- temp_buf = krealloc(entry->dci_data,
- entry->total_capacity, GFP_KERNEL);
- if (!temp_buf) {
- pr_err("diag: DCI realloc failed\n");
- break;
- } else {
- entry->dci_data = temp_buf;
- }
- }
- *(int *)(entry->dci_data+entry->data_len) =
- DCI_PKT_RSP_TYPE;
- entry->data_len += 4;
- *(int *)(entry->dci_data+entry->data_len)
- = write_len;
- entry->data_len += 4;
- memcpy(entry->dci_data+entry->data_len,
- buf+4+cmd_code_len, write_len);
- entry->data_len += write_len;
- /* delete immediate response entry */
- if (driver->smd_dci[MODEM_DATA].
- buf_in_1[8+cmd_code_len] != 0x80)
- driver->req_tracking_tbl[index].pid = 0;
- break;
+ i = diag_dci_find_client_index(curr_client_pid);
+ if (i != DCI_CLIENT_INDEX_INVALID) {
+ /* copy pkt rsp in client buf */
+ entry = &(driver->dci_client_tbl[i]);
+ if (DCI_CHK_CAPACITY(entry, 8+write_len)) {
+ pr_alert("diag: create capacity for pkt rsp\n");
+ entry->total_capacity += 8+write_len;
+ temp_buf = krealloc(entry->dci_data,
+ entry->total_capacity, GFP_KERNEL);
+ if (!temp_buf) {
+ pr_err("diag: DCI realloc failed\n");
+ return;
+ } else {
+ entry->dci_data = temp_buf;
}
}
+ *(int *)(entry->dci_data+entry->data_len) =
+ DCI_PKT_RSP_TYPE;
+ entry->data_len += 4;
+ *(int *)(entry->dci_data+entry->data_len)
+ = write_len;
+ entry->data_len += 4;
+ memcpy(entry->dci_data+entry->data_len,
+ buf+4+cmd_code_len, write_len);
+ entry->data_len += write_len;
+ /* delete immediate response entry */
+ if (driver->smd_dci[MODEM_DATA].
+ buf_in_1[8+cmd_code_len] != 0x80)
+ driver->req_tracking_tbl[index].pid = 0;
}
}
void extract_dci_events(unsigned char *buf)
{
- uint16_t event_id, event_id_packet;
- uint8_t *event_mask_ptr, byte_mask, payload_len;
- uint8_t event_data[MAX_EVENT_SIZE], timestamp[8];
- unsigned int byte_index;
- int i, bit_index, length, temp_len;
- int total_event_len, payload_len_field, timestamp_len;
+ uint16_t event_id, event_id_packet, length, temp_len;
+ uint8_t *event_mask_ptr, byte_mask, payload_len, payload_len_field;
+ uint8_t timestamp[8], bit_index, timestamp_len;
+ uint8_t event_data[MAX_EVENT_SIZE];
+ unsigned int byte_index, total_event_len, i;
struct diag_dci_client_tbl *entry;
- length = *(uint16_t *)(buf+1); /* total length of event series */
+ length = *(uint16_t *)(buf + 1); /* total length of event series */
+ if (length == 0) {
+ pr_err("diag: Incoming dci event length is invalid\n");
+ return;
+ }
temp_len = 0;
buf = buf + 3; /* start of event series */
- while (temp_len < length-1) {
- *event_data = EVENT_CMD_CODE;
- event_id_packet = *(uint16_t *)(buf+temp_len);
+ while (temp_len < (length - 1)) {
+ event_id_packet = *(uint16_t *)(buf + temp_len);
event_id = event_id_packet & 0x0FFF; /* extract 12 bits */
if (event_id_packet & 0x8000) {
timestamp_len = 2;
+ memset(timestamp, 0, 8);
} else {
timestamp_len = 8;
- memcpy(timestamp, buf+temp_len+2, 8);
+ memcpy(timestamp, buf + temp_len + 2, timestamp_len);
}
+ /* 13th and 14th bit represent the payload length */
if (((event_id_packet & 0x6000) >> 13) == 3) {
payload_len_field = 1;
payload_len = *(uint8_t *)
- (buf+temp_len+2+timestamp_len);
- memcpy(event_data+13, buf+temp_len+2+timestamp_len, 1);
- memcpy(event_data+14, buf+temp_len+2+timestamp_len+1,
- payload_len);
+ (buf + temp_len + 2 + timestamp_len);
+ if (payload_len < (MAX_EVENT_SIZE - 13)) {
+ /* copy the payload length and the payload */
+ memcpy(event_data + 12, buf + temp_len + 2 +
+ timestamp_len, 1);
+ memcpy(event_data + 13, buf + temp_len + 2 +
+ timestamp_len + 1, payload_len);
+ } else {
+ pr_err("diag: event > %d, payload_len = %d\n",
+ (MAX_EVENT_SIZE - 13), payload_len);
+ return;
+ }
} else {
payload_len_field = 0;
payload_len = (event_id_packet & 0x6000) >> 13;
- if (payload_len < MAX_EVENT_SIZE)
- memcpy(event_data+13,
- buf+temp_len+2+timestamp_len, payload_len);
- else
- pr_alert("diag: event > %d\n", MAX_EVENT_SIZE);
+ /* copy the payload */
+ memcpy(event_data + 12, buf + temp_len + 2 +
+ timestamp_len, payload_len);
}
/* 2 bytes for the event id & timestamp len is hard coded to 8,
as individual events have full timestamp */
- *(uint16_t *)(event_data+1) = 10+payload_len_field+payload_len;
- *(uint16_t *)(event_data+3) = event_id_packet & 0x7FFF;
- memcpy(event_data+5, timestamp, 8);
- total_event_len = 3 + 10 + payload_len_field + payload_len;
- byte_index = event_id/8;
+ *(uint16_t *)(event_data) = 10 +
+ payload_len_field + payload_len;
+ *(uint16_t *)(event_data + 2) = event_id_packet & 0x7FFF;
+ memcpy(event_data + 4, timestamp, 8);
+ /* 2 bytes for the event length field which is added to
+ the event data */
+ total_event_len = 2 + 10 + payload_len_field + payload_len;
+ byte_index = event_id / 8;
bit_index = event_id % 8;
byte_mask = 0x1 << bit_index;
/* parse through event mask tbl of each client and check mask */
@@ -205,7 +215,7 @@
/* copy to client buffer */
if (DCI_CHK_CAPACITY(entry,
4 + total_event_len)) {
- pr_err("diag:DCI event drop\n");
+ pr_err("diag: DCI event drop\n");
driver->dci_client_tbl[i].
dropped_events++;
return;
@@ -214,8 +224,10 @@
received_events++;
*(int *)(entry->dci_data+
entry->data_len) = DCI_EVENT_TYPE;
- memcpy(entry->dci_data+
- entry->data_len+4, event_data, total_event_len);
+ /* 4 bytes for DCI_EVENT_TYPE */
+ memcpy(entry->dci_data +
+ entry->data_len + 4, event_data
+ , total_event_len);
entry->data_len += 4 + total_event_len;
}
}
@@ -228,44 +240,37 @@
{
uint16_t log_code, item_num;
uint8_t equip_id, *log_mask_ptr, byte_mask;
- unsigned int byte_index;
- int i, found = 0;
+ unsigned int i, byte_index, byte_offset = 0;
struct diag_dci_client_tbl *entry;
- log_code = *(uint16_t *)(buf+6);
+ log_code = *(uint16_t *)(buf + 6);
equip_id = LOG_GET_EQUIP_ID(log_code);
item_num = LOG_GET_ITEM_NUM(log_code);
byte_index = item_num/8 + 2;
byte_mask = 0x01 << (item_num % 8);
+ byte_offset = (equip_id * 514) + byte_index;
+ if (byte_offset >= DCI_LOG_MASK_SIZE) {
+ pr_err("diag: Invalid byte_offset %d in dci log\n",
+ byte_offset);
+ return;
+ }
+
/* parse through log mask table of each client and check mask */
for (i = 0; i < MAX_DCI_CLIENTS; i++) {
if (driver->dci_client_tbl[i].client) {
entry = &(driver->dci_client_tbl[i]);
log_mask_ptr = entry->dci_log_mask;
- found = 0;
- while (log_mask_ptr) {
- if (*log_mask_ptr == equip_id) {
- found = 1;
- pr_debug("diag: find equip id = %x at %p\n",
- equip_id, log_mask_ptr);
- break;
- } else {
- pr_debug("diag: did not find equip id = %x at %p\n",
- equip_id, log_mask_ptr);
- log_mask_ptr += 514;
- }
- }
- if (!found)
- pr_err("diag: dci equip id not found\n");
- log_mask_ptr = log_mask_ptr + byte_index;
+ if (!log_mask_ptr)
+ return;
+ log_mask_ptr = log_mask_ptr + byte_offset;
if (*log_mask_ptr & byte_mask) {
pr_debug("\t log code %x needed by client %d",
log_code, entry->client->tgid);
/* copy to client buffer */
if (DCI_CHK_CAPACITY(entry,
- 4 + *(uint16_t *)(buf+2))) {
- pr_err("diag:DCI log drop\n");
+ 4 + *(uint16_t *)(buf + 2))) {
+ pr_err("diag: DCI log drop\n");
driver->dci_client_tbl[i].
dropped_logs++;
return;
@@ -273,9 +278,9 @@
driver->dci_client_tbl[i].received_logs++;
*(int *)(entry->dci_data+entry->data_len) =
DCI_LOG_TYPE;
- memcpy(entry->dci_data+entry->data_len+4, buf+4,
- *(uint16_t *)(buf+2));
- entry->data_len += 4 + *(uint16_t *)(buf+2);
+ memcpy(entry->dci_data + entry->data_len + 4,
+ buf + 4, *(uint16_t *)(buf + 2));
+ entry->data_len += 4 + *(uint16_t *)(buf + 2);
}
}
}
@@ -519,16 +524,8 @@
}
} else if (*(int *)temp == DCI_LOG_TYPE) {
/* find client id and table */
- for (i = 0; i < MAX_DCI_CLIENTS; i++) {
- if (driver->dci_client_tbl[i].client != NULL) {
- if (driver->dci_client_tbl[i].client->tgid ==
- current->tgid) {
- found = 1;
- break;
- }
- }
- }
- if (!found) {
+ i = diag_dci_find_client_index(current->tgid);
+ if (i == DCI_CLIENT_INDEX_INVALID) {
pr_err("diag: dci client not registered/found\n");
return ret;
}
@@ -602,16 +599,8 @@
ret = diag_send_dci_log_mask(driver->smd_cntl[MODEM_DATA].ch);
} else if (*(int *)temp == DCI_EVENT_TYPE) {
/* find client id and table */
- for (i = 0; i < MAX_DCI_CLIENTS; i++) {
- if (driver->dci_client_tbl[i].client != NULL) {
- if (driver->dci_client_tbl[i].client->tgid ==
- current->tgid) {
- found = 1;
- break;
- }
- }
- }
- if (!found) {
+ i = diag_dci_find_client_index(current->tgid);
+ if (i == DCI_CLIENT_INDEX_INVALID) {
pr_err("diag: dci client not registered/found\n");
return ret;
}
@@ -664,6 +653,22 @@
return ret;
}
+int diag_dci_find_client_index(int client_id)
+{
+ int i, ret = DCI_CLIENT_INDEX_INVALID;
+
+ for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+ if (driver->dci_client_tbl[i].client != NULL) {
+ if (driver->dci_client_tbl[i].client->tgid ==
+ client_id) {
+ ret = i;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask)
{
int i;
@@ -690,6 +695,69 @@
mutex_unlock(&dci_event_mask_mutex);
}
+void clear_client_dci_cumulative_event_mask(int client_index)
+{
+ int i, j;
+ uint8_t *update_ptr = dci_cumulative_event_mask;
+ uint8_t *event_mask_ptr, *client_event_mask_ptr, byte_mask = 0;
+ bool is_set = false;
+
+ event_mask_ptr =
+ (driver->dci_client_tbl[client_index].dci_event_mask);
+
+ mutex_lock(&dci_event_mask_mutex);
+ for (i = 0; i < DCI_EVENT_MASK_SIZE; i++) {
+ is_set = false;
+ /* Already cleared event masks need not to be considered */
+ if (*event_mask_ptr != 0) {
+ byte_mask = *event_mask_ptr;
+ } else {
+ update_ptr++;
+ event_mask_ptr++;
+ continue;
+ }
+ for (j = 0; j < MAX_DCI_CLIENTS; j++) {
+ /* continue searching for valid client */
+ if (driver->dci_client_tbl[j].client == NULL ||
+ client_index == j)
+ continue;
+ client_event_mask_ptr =
+ (driver->dci_client_tbl[j].dci_event_mask);
+ client_event_mask_ptr += i;
+ if (*client_event_mask_ptr & byte_mask) {
+ /*
+ * Break if another client has same
+ * event mask set
+ */
+ if ((*client_event_mask_ptr &
+ byte_mask) == byte_mask) {
+ is_set = true;
+ break;
+ } else {
+ byte_mask =
+ (~(*client_event_mask_ptr) &
+ byte_mask);
+ is_set = false;
+ }
+ }
+ }
+ /*
+ * Clear only if this client has event mask set else
+ * don't update cumulative event mask ptr
+ */
+ if (is_set == false)
+ *update_ptr &= ~byte_mask;
+
+ update_ptr++;
+ event_mask_ptr++;
+ }
+ event_mask_ptr =
+ (driver->dci_client_tbl[client_index].dci_event_mask);
+ memset(event_mask_ptr, 0, DCI_EVENT_MASK_SIZE);
+ mutex_unlock(&dci_event_mask_mutex);
+}
+
+
int diag_send_dci_event_mask(smd_channel_t *ch)
{
void *buf = driver->buf_event_mask_update;
@@ -769,6 +837,87 @@
mutex_unlock(&dci_log_mask_mutex);
}
+void clear_client_dci_cumulative_log_mask(int client_index)
+{
+ int i, j, k;
+ uint8_t *update_ptr = dci_cumulative_log_mask;
+ uint8_t *log_mask_ptr, *client_log_mask_ptr, byte_mask = 0;
+ bool is_set = false;
+
+ log_mask_ptr = driver->dci_client_tbl[client_index].dci_log_mask;
+
+ mutex_lock(&dci_log_mask_mutex);
+ *update_ptr = 0;
+ /* set the equipment IDs */
+ for (i = 0; i < 16; i++)
+ *(update_ptr + (i*514)) = i;
+
+ /* update cumulative log mask ptr*/
+ update_ptr += 2;
+ log_mask_ptr += 2;
+ for (i = 0; i < 16; i++) {
+ for (j = 0; j < 512; j++) {
+ is_set = false;
+ /*
+ * Already cleared log masks need
+ * not to be considered
+ */
+ if (*log_mask_ptr != 0) {
+ byte_mask = *log_mask_ptr;
+ } else {
+ update_ptr++;
+ log_mask_ptr++;
+ continue;
+ }
+ for (k = 0; k < MAX_DCI_CLIENTS; k++) {
+ /* continue searching for valid client */
+ if (driver->dci_client_tbl[k].client == NULL ||
+ client_index == k)
+ continue;
+ client_log_mask_ptr =
+ (driver->dci_client_tbl[k].dci_log_mask);
+ client_log_mask_ptr += (i*514) + 2 + j;
+ if (*client_log_mask_ptr & byte_mask) {
+ /*
+ * Break if another client has same
+ * log mask set
+ */
+ if ((*client_log_mask_ptr &
+ byte_mask) == byte_mask) {
+ is_set = true;
+ break;
+ } else {
+ byte_mask =
+ (~(*client_log_mask_ptr) &
+ byte_mask);
+ is_set = false;
+ }
+ }
+ }
+ /*
+ * Clear only if this client has log mask set else
+ * don't update cumulative log mask ptr
+ */
+ if (is_set == false) {
+ /*
+ * Update the dirty bit for the equipment
+ * whose mask is changing
+ */
+ dci_cumulative_log_mask[1+(i*514)] = 1;
+ *update_ptr &= ~byte_mask;
+ }
+
+ update_ptr++;
+ log_mask_ptr++;
+ }
+ update_ptr += 2;
+ log_mask_ptr += 2;
+ }
+ log_mask_ptr = driver->dci_client_tbl[client_index].dci_log_mask;
+ memset(log_mask_ptr, 0, DCI_LOG_MASK_SIZE);
+ mutex_unlock(&dci_log_mask_mutex);
+}
+
int diag_send_dci_log_mask(smd_channel_t *ch)
{
void *buf = driver->buf_log_mask_update;
@@ -878,10 +1027,12 @@
mutex_init(&driver->dci_mutex);
mutex_init(&dci_log_mask_mutex);
mutex_init(&dci_event_mask_mutex);
- success = diag_smd_constructor(&driver->smd_dci[MODEM_DATA],
- MODEM_DATA, SMD_DCI_TYPE);
- if (!success)
- goto err;
+ for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
+ success = diag_smd_constructor(&driver->smd_dci[i],
+ i, SMD_DCI_TYPE);
+ if (!success)
+ goto err;
+ }
if (driver->req_tracking_tbl == NULL) {
driver->req_tracking_tbl = kzalloc(dci_max_reg *
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 56d1b91..9187516 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -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
@@ -22,7 +22,9 @@
#define DCI_EVENT_TYPE -2
#define SET_LOG_MASK 1
#define DISABLE_LOG_MASK 0
-#define MAX_EVENT_SIZE 100
+#define MAX_EVENT_SIZE 512
+#define DCI_CLIENT_INDEX_INVALID -1
+
/* 16 log code categories, each has:
* 1 bytes equip id + 1 dirty byte + 512 byte max log mask
@@ -86,14 +88,17 @@
int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
int len, int index);
void extract_dci_pkt_rsp(unsigned char *buf);
+int diag_dci_find_client_index(int client_id);
/* DCI Log streaming functions */
void create_dci_log_mask_tbl(unsigned char *tbl_buf);
void update_dci_cumulative_log_mask(int offset, unsigned int byte_index,
uint8_t byte_mask);
+void clear_client_dci_cumulative_log_mask(int client_index);
int diag_send_dci_log_mask(smd_channel_t *ch);
void extract_dci_log(unsigned char *buf);
/* DCI event streaming functions */
void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask);
+void clear_client_dci_cumulative_event_mask(int client_index);
int diag_send_dci_event_mask(smd_channel_t *ch);
void extract_dci_events(unsigned char *buf);
void create_dci_event_mask_tbl(unsigned char *tbl_buf);
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 13e52df..2809900 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -245,7 +245,7 @@
static int diagchar_close(struct inode *inode, struct file *file)
{
- int i = 0;
+ int i = -1;
struct diagchar_priv *diagpriv_data = file->private_data;
pr_debug("diag: process exit %s\n", current->comm);
@@ -261,14 +261,9 @@
* This will specially help in case of ungraceful exit of any DCI client
* This call will remove any pending registrations of such client
*/
- for (i = 0; i < MAX_DCI_CLIENTS; i++) {
- if (driver->dci_client_tbl[i].client &&
- driver->dci_client_tbl[i].client->tgid ==
- current->tgid) {
- diagchar_ioctl(NULL, DIAG_IOCTL_DCI_DEINIT, 0);
- break;
- }
- }
+ if (diag_dci_find_client_index(current->tgid) !=
+ DCI_CLIENT_INDEX_INVALID)
+ diagchar_ioctl(NULL, DIAG_IOCTL_DCI_DEINIT, 0);
/* If the exiting process is the socket process */
if (driver->socket_process &&
(driver->socket_process->tgid == current->tgid)) {
@@ -530,7 +525,7 @@
long diagchar_ioctl(struct file *filp,
unsigned int iocmd, unsigned long ioarg)
{
- int i, j, temp, success = -1, status;
+ int i, j, temp, success = -1, status, index = -1;
unsigned int count_entries = 0, interim_count = 0;
void *temp_buf;
uint16_t support_list = 0;
@@ -731,19 +726,40 @@
return driver->dci_client_id;
} else if (iocmd == DIAG_IOCTL_DCI_DEINIT) {
success = -1;
- /* Delete this process from DCI table */
+ /*
+ * Clear log/event masks and send updated
+ * masks to peripherals
+ */
mutex_lock(&driver->dci_mutex);
+ index = diag_dci_find_client_index(current->tgid);
+ if (index != DCI_CLIENT_INDEX_INVALID) {
+ /* clear respective cumulative log masks */
+ clear_client_dci_cumulative_log_mask(index);
+ /* send updated log mask to peripherals */
+ success =
+ diag_send_dci_log_mask(driver->smd_cntl[MODEM_DATA].ch);
+ if (success != DIAG_DCI_NO_ERROR) {
+ mutex_unlock(&driver->dci_mutex);
+ return success;
+ }
+ /* clear respective cumulative event masks */
+ clear_client_dci_cumulative_event_mask(index);
+ /* send updated event mask to peripherals */
+ success =
+ diag_send_dci_event_mask(
+ driver->smd_cntl[MODEM_DATA].ch);
+ if (success != DIAG_DCI_NO_ERROR) {
+ mutex_unlock(&driver->dci_mutex);
+ return success;
+ }
+ }
+ /* Delete this process from DCI table */
for (i = 0; i < dci_max_reg; i++)
if (driver->req_tracking_tbl[i].pid == current->tgid)
driver->req_tracking_tbl[i].pid = 0;
- for (i = 0; i < MAX_DCI_CLIENTS; i++) {
- if (driver->dci_client_tbl[i].client &&
- driver->dci_client_tbl[i].client->tgid ==
- current->tgid) {
- driver->dci_client_tbl[i].client = NULL;
- success = i;
- break;
- }
+ if (index != DCI_CLIENT_INDEX_INVALID) {
+ driver->dci_client_tbl[index].client = NULL;
+ success = index;
}
if (success >= 0)
driver->num_dci_client--;
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 3da06a5..1facf24 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -1523,6 +1523,9 @@
}
break;
default:
+ pr_err("Unknown mode of operation %d received, exiting now\n",
+ mode);
+ return -EINVAL;
break;
}
@@ -1686,6 +1689,8 @@
}
break;
default:
+ pr_err("Unknown algorithms %d received, exiting now\n", alg);
+ return -EINVAL;
break;
}
@@ -1893,6 +1898,8 @@
0, NULL);
break;
default:
+ pr_err("Unknown algorithms %d received, exiting now\n", alg);
+ return -EINVAL;
break;
}
@@ -2247,6 +2254,10 @@
if (q_req->mode != QCE_MODE_CCM) {
ivsize = crypto_aead_ivsize(aead);
auth_cmdlistinfo = &pce_dev->ce_sps.cmdlistptr.aead_sha1_hmac;
+ if (auth_cmdlistinfo == NULL) {
+ pr_err("Received NULL cmdlist, exiting now\n");
+ return -EINVAL;
+ }
}
ce_burst_size = pce_dev->ce_sps.ce_burst_size;
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 50d454c..41ab8dc 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -595,6 +595,9 @@
sreq.authklen = qcedev_areq->sha_op_req.authklen;
break;
default:
+ pr_err("Algorithm %d not supported, exiting\n",
+ qcedev_areq->sha_op_req.alg);
+ return -EINVAL;
break;
};
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 7e063ca..05ef87c 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -1175,6 +1175,8 @@
sreq.authklen = SHA_HMAC_KEY_SIZE;
break;
default:
+ pr_err("Algorithm %d not supported, exiting", sha_ctx->alg);
+ ret = -1;
break;
};
ret = qce_process_sha_req(cp->qce, &sreq);
@@ -1240,6 +1242,7 @@
if (rctx->data == NULL) {
pr_err("Mem Alloc fail rctx->data, err %ld\n",
PTR_ERR(rctx->data));
+ kzfree(qreq.assoc);
return -ENOMEM;
}
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 8f03ccb..e578b0e 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -817,9 +817,9 @@
{
int status = -EINVAL;
- /* Don't wait forever, set a max (10 sec) value for now */
+ /* Don't wait forever, set a max of Z180_IDLE_TIMEOUT */
if (msecs == -1)
- msecs = 10 * MSEC_PER_SEC;
+ msecs = Z180_IDLE_TIMEOUT;
mutex_unlock(&device->mutex);
status = z180_wait(device, context, timestamp, msecs);
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 05ef4b0..714cd8c 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -28,13 +28,26 @@
#define UHID_BUFSIZE 32
struct uhid_device {
+ struct mutex devlock;
+ bool running;
+
+ __u8 *rd_data;
+ uint rd_size;
+
struct hid_device *hid;
+ struct uhid_event input_buf;
wait_queue_head_t waitq;
spinlock_t qlock;
__u8 head;
__u8 tail;
struct uhid_event *outq[UHID_BUFSIZE];
+
+ struct mutex report_lock;
+ wait_queue_head_t report_wait;
+ atomic_t report_done;
+ atomic_t report_id;
+ struct uhid_event report_buf;
};
static struct miscdevice uhid_misc;
@@ -73,6 +86,316 @@
return 0;
}
+static int uhid_hid_start(struct hid_device *hid)
+{
+ struct uhid_device *uhid = hid->driver_data;
+
+ return uhid_queue_event(uhid, UHID_START);
+}
+
+static void uhid_hid_stop(struct hid_device *hid)
+{
+ struct uhid_device *uhid = hid->driver_data;
+
+ hid->claimed = 0;
+ uhid_queue_event(uhid, UHID_STOP);
+}
+
+static int uhid_hid_open(struct hid_device *hid)
+{
+ struct uhid_device *uhid = hid->driver_data;
+
+ return uhid_queue_event(uhid, UHID_OPEN);
+}
+
+static void uhid_hid_close(struct hid_device *hid)
+{
+ struct uhid_device *uhid = hid->driver_data;
+
+ uhid_queue_event(uhid, UHID_CLOSE);
+}
+
+static int uhid_hid_input(struct input_dev *input, unsigned int type,
+ unsigned int code, int value)
+{
+ struct hid_device *hid = input_get_drvdata(input);
+ struct uhid_device *uhid = hid->driver_data;
+ unsigned long flags;
+ struct uhid_event *ev;
+
+ ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+ if (!ev)
+ return -ENOMEM;
+
+ ev->type = UHID_OUTPUT_EV;
+ ev->u.output_ev.type = type;
+ ev->u.output_ev.code = code;
+ ev->u.output_ev.value = value;
+
+ spin_lock_irqsave(&uhid->qlock, flags);
+ uhid_queue(uhid, ev);
+ spin_unlock_irqrestore(&uhid->qlock, flags);
+
+ return 0;
+}
+
+static int uhid_hid_parse(struct hid_device *hid)
+{
+ struct uhid_device *uhid = hid->driver_data;
+
+ return hid_parse_report(hid, uhid->rd_data, uhid->rd_size);
+}
+
+static int uhid_hid_get_raw(struct hid_device *hid, unsigned char rnum,
+ __u8 *buf, size_t count, unsigned char rtype)
+{
+ struct uhid_device *uhid = hid->driver_data;
+ __u8 report_type;
+ struct uhid_event *ev;
+ unsigned long flags;
+ int ret;
+ size_t uninitialized_var(len);
+ struct uhid_feature_answer_req *req;
+
+ if (!uhid->running)
+ return -EIO;
+
+ switch (rtype) {
+ case HID_FEATURE_REPORT:
+ report_type = UHID_FEATURE_REPORT;
+ break;
+ case HID_OUTPUT_REPORT:
+ report_type = UHID_OUTPUT_REPORT;
+ break;
+ case HID_INPUT_REPORT:
+ report_type = UHID_INPUT_REPORT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = mutex_lock_interruptible(&uhid->report_lock);
+ if (ret)
+ return ret;
+
+ ev = kzalloc(sizeof(*ev), GFP_KERNEL);
+ if (!ev) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+ spin_lock_irqsave(&uhid->qlock, flags);
+ ev->type = UHID_FEATURE;
+ ev->u.feature.id = atomic_inc_return(&uhid->report_id);
+ ev->u.feature.rnum = rnum;
+ ev->u.feature.rtype = report_type;
+
+ atomic_set(&uhid->report_done, 0);
+ uhid_queue(uhid, ev);
+ spin_unlock_irqrestore(&uhid->qlock, flags);
+
+ ret = wait_event_interruptible_timeout(uhid->report_wait,
+ atomic_read(&uhid->report_done), 5 * HZ);
+
+ /*
+ * Make sure "uhid->running" is cleared on shutdown before
+ * "uhid->report_done" is set.
+ */
+ smp_rmb();
+ if (!ret || !uhid->running) {
+ ret = -EIO;
+ } else if (ret < 0) {
+ ret = -ERESTARTSYS;
+ } else {
+ spin_lock_irqsave(&uhid->qlock, flags);
+ req = &uhid->report_buf.u.feature_answer;
+
+ if (req->err) {
+ ret = -EIO;
+ } else {
+ ret = 0;
+ len = min(count,
+ min_t(size_t, req->size, UHID_DATA_MAX));
+ memcpy(buf, req->data, len);
+ }
+
+ spin_unlock_irqrestore(&uhid->qlock, flags);
+ }
+
+ atomic_set(&uhid->report_done, 1);
+
+unlock:
+ mutex_unlock(&uhid->report_lock);
+ return ret ? ret : len;
+}
+
+static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count,
+ unsigned char report_type)
+{
+ struct uhid_device *uhid = hid->driver_data;
+ __u8 rtype;
+ unsigned long flags;
+ struct uhid_event *ev;
+
+ switch (report_type) {
+ case HID_FEATURE_REPORT:
+ rtype = UHID_FEATURE_REPORT;
+ break;
+ case HID_OUTPUT_REPORT:
+ rtype = UHID_OUTPUT_REPORT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (count < 1 || count > UHID_DATA_MAX)
+ return -EINVAL;
+
+ ev = kzalloc(sizeof(*ev), GFP_KERNEL);
+ if (!ev)
+ return -ENOMEM;
+
+ ev->type = UHID_OUTPUT;
+ ev->u.output.size = count;
+ ev->u.output.rtype = rtype;
+ memcpy(ev->u.output.data, buf, count);
+
+ spin_lock_irqsave(&uhid->qlock, flags);
+ uhid_queue(uhid, ev);
+ spin_unlock_irqrestore(&uhid->qlock, flags);
+
+ return count;
+}
+
+static struct hid_ll_driver uhid_hid_driver = {
+ .start = uhid_hid_start,
+ .stop = uhid_hid_stop,
+ .open = uhid_hid_open,
+ .close = uhid_hid_close,
+ .hidinput_input_event = uhid_hid_input,
+ .parse = uhid_hid_parse,
+};
+
+static int uhid_dev_create(struct uhid_device *uhid,
+ const struct uhid_event *ev)
+{
+ struct hid_device *hid;
+ int ret;
+
+ if (uhid->running)
+ return -EALREADY;
+
+ uhid->rd_size = ev->u.create.rd_size;
+ if (uhid->rd_size <= 0 || uhid->rd_size > HID_MAX_DESCRIPTOR_SIZE)
+ return -EINVAL;
+
+ uhid->rd_data = kmalloc(uhid->rd_size, GFP_KERNEL);
+ if (!uhid->rd_data)
+ return -ENOMEM;
+
+ if (copy_from_user(uhid->rd_data, ev->u.create.rd_data,
+ uhid->rd_size)) {
+ ret = -EFAULT;
+ goto err_free;
+ }
+
+ hid = hid_allocate_device();
+ if (IS_ERR(hid)) {
+ ret = PTR_ERR(hid);
+ goto err_free;
+ }
+
+ strncpy(hid->name, ev->u.create.name, 127);
+ hid->name[127] = 0;
+ strncpy(hid->phys, ev->u.create.phys, 63);
+ hid->phys[63] = 0;
+ strncpy(hid->uniq, ev->u.create.uniq, 63);
+ hid->uniq[63] = 0;
+
+ hid->ll_driver = &uhid_hid_driver;
+ hid->hid_get_raw_report = uhid_hid_get_raw;
+ hid->hid_output_raw_report = uhid_hid_output_raw;
+ hid->bus = ev->u.create.bus;
+ hid->vendor = ev->u.create.vendor;
+ hid->product = ev->u.create.product;
+ hid->version = ev->u.create.version;
+ hid->country = ev->u.create.country;
+ hid->driver_data = uhid;
+ hid->dev.parent = uhid_misc.this_device;
+
+ uhid->hid = hid;
+ uhid->running = true;
+
+ ret = hid_add_device(hid);
+ if (ret) {
+ hid_err(hid, "Cannot register HID device\n");
+ goto err_hid;
+ }
+
+ return 0;
+
+err_hid:
+ hid_destroy_device(hid);
+ uhid->hid = NULL;
+ uhid->running = false;
+err_free:
+ kfree(uhid->rd_data);
+ return ret;
+}
+
+static int uhid_dev_destroy(struct uhid_device *uhid)
+{
+ if (!uhid->running)
+ return -EINVAL;
+
+ /* clear "running" before setting "report_done" */
+ uhid->running = false;
+ smp_wmb();
+ atomic_set(&uhid->report_done, 1);
+ wake_up_interruptible(&uhid->report_wait);
+
+ hid_destroy_device(uhid->hid);
+ kfree(uhid->rd_data);
+
+ return 0;
+}
+
+static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)
+{
+ if (!uhid->running)
+ return -EINVAL;
+
+ hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data,
+ min_t(size_t, ev->u.input.size, UHID_DATA_MAX), 0);
+
+ return 0;
+}
+
+static int uhid_dev_feature_answer(struct uhid_device *uhid,
+ struct uhid_event *ev)
+{
+ unsigned long flags;
+
+ if (!uhid->running)
+ return -EINVAL;
+
+ spin_lock_irqsave(&uhid->qlock, flags);
+
+ /* id for old report; drop it silently */
+ if (atomic_read(&uhid->report_id) != ev->u.feature_answer.id)
+ goto unlock;
+ if (atomic_read(&uhid->report_done))
+ goto unlock;
+
+ memcpy(&uhid->report_buf, ev, sizeof(*ev));
+ atomic_set(&uhid->report_done, 1);
+ wake_up_interruptible(&uhid->report_wait);
+
+unlock:
+ spin_unlock_irqrestore(&uhid->qlock, flags);
+ return 0;
+}
+
static int uhid_char_open(struct inode *inode, struct file *file)
{
struct uhid_device *uhid;
@@ -81,8 +404,13 @@
if (!uhid)
return -ENOMEM;
+ mutex_init(&uhid->devlock);
+ mutex_init(&uhid->report_lock);
spin_lock_init(&uhid->qlock);
init_waitqueue_head(&uhid->waitq);
+ init_waitqueue_head(&uhid->report_wait);
+ uhid->running = false;
+ atomic_set(&uhid->report_done, 1);
file->private_data = uhid;
nonseekable_open(inode, file);
@@ -95,6 +423,8 @@
struct uhid_device *uhid = file->private_data;
unsigned int i;
+ uhid_dev_destroy(uhid);
+
for (i = 0; i < UHID_BUFSIZE; ++i)
kfree(uhid->outq[i]);
@@ -106,17 +436,106 @@
static ssize_t uhid_char_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
- return 0;
+ struct uhid_device *uhid = file->private_data;
+ int ret;
+ unsigned long flags;
+ size_t len;
+
+ /* they need at least the "type" member of uhid_event */
+ if (count < sizeof(__u32))
+ return -EINVAL;
+
+try_again:
+ if (file->f_flags & O_NONBLOCK) {
+ if (uhid->head == uhid->tail)
+ return -EAGAIN;
+ } else {
+ ret = wait_event_interruptible(uhid->waitq,
+ uhid->head != uhid->tail);
+ if (ret)
+ return ret;
+ }
+
+ ret = mutex_lock_interruptible(&uhid->devlock);
+ if (ret)
+ return ret;
+
+ if (uhid->head == uhid->tail) {
+ mutex_unlock(&uhid->devlock);
+ goto try_again;
+ } else {
+ len = min(count, sizeof(**uhid->outq));
+ if (copy_to_user(buffer, uhid->outq[uhid->tail], len)) {
+ ret = -EFAULT;
+ } else {
+ kfree(uhid->outq[uhid->tail]);
+ uhid->outq[uhid->tail] = NULL;
+
+ spin_lock_irqsave(&uhid->qlock, flags);
+ uhid->tail = (uhid->tail + 1) % UHID_BUFSIZE;
+ spin_unlock_irqrestore(&uhid->qlock, flags);
+ }
+ }
+
+ mutex_unlock(&uhid->devlock);
+ return ret ? ret : len;
}
static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
- return 0;
+ struct uhid_device *uhid = file->private_data;
+ int ret;
+ size_t len;
+
+ /* we need at least the "type" member of uhid_event */
+ if (count < sizeof(__u32))
+ return -EINVAL;
+
+ ret = mutex_lock_interruptible(&uhid->devlock);
+ if (ret)
+ return ret;
+
+ memset(&uhid->input_buf, 0, sizeof(uhid->input_buf));
+ len = min(count, sizeof(uhid->input_buf));
+ if (copy_from_user(&uhid->input_buf, buffer, len)) {
+ ret = -EFAULT;
+ goto unlock;
+ }
+
+ switch (uhid->input_buf.type) {
+ case UHID_CREATE:
+ ret = uhid_dev_create(uhid, &uhid->input_buf);
+ break;
+ case UHID_DESTROY:
+ ret = uhid_dev_destroy(uhid);
+ break;
+ case UHID_INPUT:
+ ret = uhid_dev_input(uhid, &uhid->input_buf);
+ break;
+ case UHID_FEATURE_ANSWER:
+ ret = uhid_dev_feature_answer(uhid, &uhid->input_buf);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ }
+
+unlock:
+ mutex_unlock(&uhid->devlock);
+
+ /* return "count" not "len" to not confuse the caller */
+ return ret ? ret : count;
}
static unsigned int uhid_char_poll(struct file *file, poll_table *wait)
{
+ struct uhid_device *uhid = file->private_data;
+
+ poll_wait(file, &uhid->waitq, wait);
+
+ if (uhid->head != uhid->tail)
+ return POLLIN | POLLRDNORM;
+
return 0;
}
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index ca0a439..a77dacb 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-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
@@ -29,13 +29,14 @@
#include <linux/mutex.h>
#include <linux/timer.h>
#include <linux/slab.h>
-#include <mach/board.h>
-#include <mach/gpiomux.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_i2c.h>
+#include <linux/of_gpio.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
MODULE_LICENSE("GPL v2");
MODULE_VERSION("0.2");
@@ -131,6 +132,7 @@
#define DEFAULT_CLK_RATE (19200000)
#define I2C_STATUS_CLK_STATE 13
#define QUP_OUT_FIFO_NOT_EMPTY 0x10
+#define I2C_GPIOS_DT_CNT (2) /* sda and scl */
static char const * const i2c_rsrcs[] = {"i2c_clk", "i2c_sda"};
@@ -1088,6 +1090,72 @@
return ret;
}
+enum msm_i2c_dt_entry_status {
+ DT_REQUIRED,
+ DT_SUGGESTED,
+ DT_OPTIONAL,
+};
+
+enum msm_i2c_dt_entry_type {
+ DT_U32,
+ DT_GPIO,
+};
+
+struct msm_i2c_dt_to_pdata_map {
+ const char *dt_name;
+ int *ptr_data;
+ enum msm_i2c_dt_entry_status status;
+ enum msm_i2c_dt_entry_type type;
+ int default_val;
+};
+
+int __devinit msm_i2c_rsrcs_dt_to_pdata_map(struct platform_device *pdev,
+ struct msm_i2c_platform_data *pdata, int *gpios)
+{
+ int ret, err = 0;
+ struct device_node *node = pdev->dev.of_node;
+ struct msm_i2c_dt_to_pdata_map *itr;
+ struct msm_i2c_dt_to_pdata_map map[] = {
+ {"qcom,i2c-bus-freq", &pdata->clk_freq , DT_REQUIRED , DT_U32 , 0},
+ {"cell-index" , &pdev->id , DT_REQUIRED , DT_U32 , -1},
+ {"qcom,i2c-src-freq", &pdata->src_clk_rate, DT_SUGGESTED, DT_U32, 0},
+ {"qcom,scl-gpio" , gpios , DT_OPTIONAL , DT_GPIO, -1},
+ {"qcom,sda-gpio" , gpios + 1 , DT_OPTIONAL , DT_GPIO, -1},
+ {NULL , NULL , 0 , 0 , 0},
+ };
+
+ for (itr = map; itr->dt_name ; ++itr) {
+ if (itr->type == DT_GPIO) {
+ ret = of_get_named_gpio(node, itr->dt_name, 0);
+ if (ret >= 0) {
+ *itr->ptr_data = ret;
+ ret = 0;
+ }
+ } else {
+ ret = of_property_read_u32(node, itr->dt_name,
+ itr->ptr_data);
+ }
+
+ dev_dbg(&pdev->dev, "DT entry ret:%d name:%s val:%d\n",
+ ret, itr->dt_name, *itr->ptr_data);
+
+ if (ret) {
+ *itr->ptr_data = itr->default_val;
+
+ if (itr->status < DT_OPTIONAL) {
+ dev_err(&pdev->dev, "Missing '%s' DT entry\n",
+ itr->dt_name);
+
+ /* cont on err to dump all missing entries */
+ if (itr->status == DT_REQUIRED && !err)
+ err = ret;
+ }
+ }
+ }
+
+ return err;
+}
+
static u32
qup_i2c_func(struct i2c_adapter *adap)
{
@@ -1106,28 +1174,23 @@
struct resource *qup_mem, *gsbi_mem, *qup_io, *gsbi_io, *res;
struct resource *in_irq, *out_irq, *err_irq;
struct clk *clk, *pclk;
- int ret = 0;
- int i;
+ int ret = 0;
+ int i;
+ int dt_gpios[I2C_GPIOS_DT_CNT];
+ bool use_device_tree = pdev->dev.of_node;
struct msm_i2c_platform_data *pdata;
gsbi_mem = NULL;
dev_dbg(&pdev->dev, "qup_i2c_probe\n");
- if (pdev->dev.of_node) {
- struct device_node *node = pdev->dev.of_node;
- pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (use_device_tree) {
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
- ret = of_property_read_u32(node, "qcom,i2c-bus-freq",
- &pdata->clk_freq);
+
+ ret = msm_i2c_rsrcs_dt_to_pdata_map(pdev, pdata, dt_gpios);
if (ret)
goto get_res_failed;
- ret = of_property_read_u32(node, "cell-index", &pdev->id);
- if (ret)
- goto get_res_failed;
- /* Optional property */
- of_property_read_u32(node, "qcom,i2c-src-freq",
- &pdata->src_clk_rate);
} else
pdata = pdev->dev.platform_data;
@@ -1247,9 +1310,13 @@
}
for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {
- res = platform_get_resource_byname(pdev, IORESOURCE_IO,
- i2c_rsrcs[i]);
- dev->i2c_gpios[i] = res ? res->start : -1;
+ if (use_device_tree && i < I2C_GPIOS_DT_CNT) {
+ dev->i2c_gpios[i] = dt_gpios[i];
+ } else {
+ res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+ i2c_rsrcs[i]);
+ dev->i2c_gpios[i] = res ? res->start : -1;
+ }
}
platform_set_drvdata(pdev, dev);
@@ -1261,8 +1328,7 @@
if (dev->pdata->src_clk_rate <= 0) {
dev_info(&pdev->dev,
- "No src_clk_rate specified in platfrom data or "
- "qcom,i2c-src-freq in DT\n");
+ "No src_clk_rate specified in platfrom data\n");
dev_info(&pdev->dev, "Using default clock rate %dHz\n",
DEFAULT_CLK_RATE);
dev->pdata->src_clk_rate = DEFAULT_CLK_RATE;
diff --git a/drivers/iommu/msm_iommu-v1.c b/drivers/iommu/msm_iommu-v1.c
index 15a81ed..24d2854 100644
--- a/drivers/iommu/msm_iommu-v1.c
+++ b/drivers/iommu/msm_iommu-v1.c
@@ -202,7 +202,6 @@
struct msm_iommu_drvdata *iommu_drvdata;
struct msm_iommu_ctx_drvdata *ctx_drvdata;
int ret = 0;
- int asid;
list_for_each_entry(ctx_drvdata, &priv->list_attached, attached_elm) {
BUG_ON(!ctx_drvdata->pdev || !ctx_drvdata->pdev->dev.parent);
@@ -215,11 +214,8 @@
if (ret)
goto fail;
- asid = GET_CB_CONTEXTIDR_ASID(iommu_drvdata->base,
- ctx_drvdata->num);
-
SET_TLBIVA(iommu_drvdata->base, ctx_drvdata->num,
- asid | (va & CB_TLBIVA_VA));
+ ctx_drvdata->asid | (va & CB_TLBIVA_VA));
mb();
__sync_tlb(iommu_drvdata->base, ctx_drvdata->num);
__disable_clocks(iommu_drvdata);
@@ -234,7 +230,6 @@
struct msm_iommu_drvdata *iommu_drvdata;
struct msm_iommu_ctx_drvdata *ctx_drvdata;
int ret = 0;
- int asid;
list_for_each_entry(ctx_drvdata, &priv->list_attached, attached_elm) {
BUG_ON(!ctx_drvdata->pdev || !ctx_drvdata->pdev->dev.parent);
@@ -246,10 +241,8 @@
if (ret)
goto fail;
- asid = GET_CB_CONTEXTIDR_ASID(iommu_drvdata->base,
- ctx_drvdata->num);
-
- SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num, asid);
+ SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num,
+ ctx_drvdata->asid);
mb();
__sync_tlb(iommu_drvdata->base, ctx_drvdata->num);
__disable_clocks(iommu_drvdata);
@@ -342,69 +335,46 @@
static void msm_iommu_assign_ASID(const struct msm_iommu_drvdata *iommu_drvdata,
struct msm_iommu_ctx_drvdata *curr_ctx,
- phys_addr_t pgtable)
+ struct msm_priv *priv)
{
- struct platform_device *pdev;
- struct device_node *child;
- struct msm_iommu_ctx_drvdata *ctx;
unsigned int found = 0;
void __iomem *base = iommu_drvdata->base;
- struct device_node *iommu_node = iommu_drvdata->dev->of_node;
- unsigned int asid;
+ unsigned int i;
unsigned int ncb = iommu_drvdata->ncb;
+ struct msm_iommu_ctx_drvdata *tmp_drvdata;
/* Find if this page table is used elsewhere, and re-use ASID */
- for_each_child_of_node(iommu_node, child) {
- pdev = of_find_device_by_node(child);
- ctx = dev_get_drvdata(&pdev->dev);
+ if (!list_empty(&priv->list_attached)) {
+ tmp_drvdata = list_first_entry(&priv->list_attached,
+ struct msm_iommu_ctx_drvdata, attached_elm);
- if (ctx->secure_context) {
- of_dev_put(pdev);
- continue;
- }
+ ++iommu_drvdata->asid[tmp_drvdata->asid - 1];
+ curr_ctx->asid = tmp_drvdata->asid;
- if ((ctx != curr_ctx) &&
- (GET_CB_TTBR0_ADDR(base, ctx->num) == pgtable)) {
- SET_CB_CONTEXTIDR_ASID(base, curr_ctx->num, ctx->asid);
- curr_ctx->asid = ctx->asid;
- found = 1;
- of_dev_put(pdev);
- of_node_put(child);
- break;
- }
- of_dev_put(pdev);
+ SET_CB_CONTEXTIDR_ASID(base, curr_ctx->num, curr_ctx->asid);
+ found = 1;
}
/* If page table is new, find an unused ASID */
if (!found) {
- for (asid = 1; asid < ncb + 1; ++asid) {
- found = 0;
- for_each_child_of_node(iommu_node, child) {
- pdev = of_find_device_by_node(child);
- ctx = dev_get_drvdata(&pdev->dev);
+ for (i = 0; i < ncb; ++i) {
+ if (iommu_drvdata->asid[i] == 0) {
+ ++iommu_drvdata->asid[i];
+ curr_ctx->asid = i + 1;
- if (ctx != curr_ctx && ctx->asid == asid) {
- found = 1;
- of_dev_put(pdev);
- of_node_put(child);
- break;
- }
- of_dev_put(pdev);
- }
- if (!found) {
SET_CB_CONTEXTIDR_ASID(base, curr_ctx->num,
- asid);
- curr_ctx->asid = asid;
+ curr_ctx->asid);
+ found = 1;
break;
}
}
- BUG_ON(found);
+ BUG_ON(!found);
}
}
static void __program_context(struct msm_iommu_drvdata *iommu_drvdata,
struct msm_iommu_ctx_drvdata *ctx_drvdata,
- phys_addr_t pgtable, int redirect, bool is_secure)
+ struct msm_priv *priv, bool is_secure)
{
unsigned int prrr, nmrr;
unsigned int pn;
@@ -413,6 +383,7 @@
unsigned int ctx = ctx_drvdata->num;
u32 *sids = ctx_drvdata->sids;
int len = ctx_drvdata->nsid;
+ phys_addr_t pgtable = __pa(priv->pt.fl_table);
__reset_context(base, ctx);
@@ -443,7 +414,7 @@
/* Configure page tables as inner-cacheable and shareable to reduce
* the TLB miss penalty.
*/
- if (redirect) {
+ if (priv->pt.redirect) {
SET_CB_TTBR0_S(base, ctx, 1);
SET_CB_TTBR0_NOS(base, ctx, 1);
SET_CB_TTBR0_IRGN1(base, ctx, 0); /* WB, WA */
@@ -489,7 +460,7 @@
}
- msm_iommu_assign_ASID(iommu_drvdata, ctx_drvdata, pn);
+ msm_iommu_assign_ASID(iommu_drvdata, ctx_drvdata, priv);
/* Enable the MMU */
SET_CB_SCTLR_M(base, ctx, 1);
@@ -535,27 +506,6 @@
mutex_unlock(&msm_iommu_lock);
}
-static int msm_iommu_ctx_attached(struct device *dev)
-{
- struct platform_device *pdev;
- struct device_node *child;
- struct msm_iommu_ctx_drvdata *ctx;
-
- for_each_child_of_node(dev->of_node, child) {
- pdev = of_find_device_by_node(child);
-
- ctx = dev_get_drvdata(&pdev->dev);
- if (ctx->attached_domain) {
- of_dev_put(pdev);
- of_node_put(child);
- return 1;
- }
- of_dev_put(pdev);
- }
-
- return 0;
-}
-
static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
{
struct msm_priv *priv;
@@ -603,8 +553,8 @@
goto fail;
}
-
- if (!msm_iommu_ctx_attached(dev->parent)) {
+ /* We can only do this once */
+ if (!iommu_drvdata->ctx_attach_count) {
if (!is_secure) {
iommu_halt(iommu_drvdata);
__program_iommu(iommu_drvdata->base);
@@ -624,8 +574,7 @@
iommu_halt(iommu_drvdata);
- __program_context(iommu_drvdata, ctx_drvdata, __pa(priv->pt.fl_table),
- priv->pt.redirect, is_secure);
+ __program_context(iommu_drvdata, ctx_drvdata, priv, is_secure);
iommu_resume(iommu_drvdata);
@@ -633,6 +582,7 @@
list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
ctx_drvdata->attached_domain = domain;
+ ++iommu_drvdata->ctx_attach_count;
mutex_unlock(&msm_iommu_lock);
@@ -671,6 +621,9 @@
is_secure = iommu_drvdata->sec_id != -1;
SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num, ctx_drvdata->asid);
+
+ BUG_ON(iommu_drvdata->asid[ctx_drvdata->asid - 1] == 0);
+ iommu_drvdata->asid[ctx_drvdata->asid - 1]--;
ctx_drvdata->asid = -1;
iommu_halt(iommu_drvdata);
@@ -687,7 +640,8 @@
list_del_init(&ctx_drvdata->attached_elm);
ctx_drvdata->attached_domain = NULL;
-
+ BUG_ON(iommu_drvdata->ctx_attach_count == 0);
+ --iommu_drvdata->ctx_attach_count;
fail:
mutex_unlock(&msm_iommu_lock);
}
diff --git a/drivers/iommu/msm_iommu_dev-v1.c b/drivers/iommu/msm_iommu_dev-v1.c
index 3f9f1c4..f994413 100644
--- a/drivers/iommu/msm_iommu_dev-v1.c
+++ b/drivers/iommu/msm_iommu_dev-v1.c
@@ -104,6 +104,15 @@
pr_err("Failed to create %s device\n", child->name);
}
+ drvdata->asid = devm_kzalloc(&pdev->dev, drvdata->ncb * sizeof(int),
+ GFP_KERNEL);
+
+ if (!drvdata->asid) {
+ pr_err("Unable to get memory for asid array\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
ret = of_property_read_string(pdev->dev.of_node, "label",
&drvdata->name);
if (ret)
diff --git a/drivers/iommu/msm_iommu_pagetable.c b/drivers/iommu/msm_iommu_pagetable.c
index 99841cd..b32bd26 100644
--- a/drivers/iommu/msm_iommu_pagetable.c
+++ b/drivers/iommu/msm_iommu_pagetable.c
@@ -357,14 +357,14 @@
return ret;
}
-static unsigned int get_phys_addr(struct scatterlist *sg)
+static phys_addr_t get_phys_addr(struct scatterlist *sg)
{
/*
* Try sg_dma_address first so that we can
* map carveout regions that do not have a
* struct page associated with them.
*/
- unsigned int pa = sg_dma_address(sg);
+ phys_addr_t pa = sg_dma_address(sg);
if (pa == 0)
pa = sg_phys(sg);
return pa;
@@ -380,7 +380,7 @@
int msm_iommu_pagetable_map_range(struct iommu_pt *pt, unsigned int va,
struct scatterlist *sg, unsigned int len, int prot)
{
- unsigned int pa;
+ phys_addr_t pa;
unsigned int offset = 0;
unsigned long *fl_pte;
unsigned long fl_offset;
diff --git a/drivers/iommu/msm_iommu_sec.c b/drivers/iommu/msm_iommu_sec.c
index 4e55bd6..29cf0c1 100644
--- a/drivers/iommu/msm_iommu_sec.c
+++ b/drivers/iommu/msm_iommu_sec.c
@@ -359,26 +359,30 @@
if (ret)
goto fail;
- ret = __enable_clocks(iommu_drvdata);
- if (ret) {
- regulator_disable(iommu_drvdata->gdsc);
- goto fail;
- }
+ /* We can only do this once */
+ if (!iommu_drvdata->ctx_attach_count) {
+ ret = __enable_clocks(iommu_drvdata);
+ if (ret) {
+ regulator_disable(iommu_drvdata->gdsc);
+ goto fail;
+ }
- ret = msm_iommu_sec_program_iommu(iommu_drvdata->sec_id);
+ ret = msm_iommu_sec_program_iommu(iommu_drvdata->sec_id);
- /* bfb settings are always programmed by HLOS */
- program_iommu_bfb_settings(iommu_drvdata->base,
- iommu_drvdata->bfb_settings);
+ /* bfb settings are always programmed by HLOS */
+ program_iommu_bfb_settings(iommu_drvdata->base,
+ iommu_drvdata->bfb_settings);
- __disable_clocks(iommu_drvdata);
- if (ret) {
- regulator_disable(iommu_drvdata->gdsc);
- goto fail;
+ __disable_clocks(iommu_drvdata);
+ if (ret) {
+ regulator_disable(iommu_drvdata->gdsc);
+ goto fail;
+ }
}
list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
ctx_drvdata->attached_domain = domain;
+ ++iommu_drvdata->ctx_attach_count;
mutex_unlock(&msm_iommu_lock);
@@ -410,7 +414,8 @@
ctx_drvdata->attached_domain = NULL;
regulator_disable(iommu_drvdata->gdsc);
-
+ BUG_ON(iommu_drvdata->ctx_attach_count == 0);
+ --iommu_drvdata->ctx_attach_count;
fail:
mutex_unlock(&msm_iommu_lock);
}
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index fb1882c..9e0a147 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -62,7 +62,7 @@
#define WLED_OP_FDBCK_MASK 0x07
#define WLED_OP_FDBCK_BIT_SHFT 0x00
-#define WLED_MAX_LEVEL 255
+#define WLED_MAX_LEVEL 4095
#define WLED_8_BIT_MASK 0xFF
#define WLED_4_BIT_MASK 0x0F
#define WLED_8_BIT_SHFT 0x08
@@ -365,8 +365,8 @@
static int qpnp_wled_set(struct qpnp_led_data *led)
{
- int rc, duty;
- u8 level, val, i, num_wled_strings;
+ int rc, duty, level;
+ u8 val, i, num_wled_strings;
level = led->cdev.brightness;
diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c
index 63ab4bf..6b27048 100644
--- a/drivers/media/platform/msm/camera_v2/camera/camera.c
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.c
@@ -314,7 +314,7 @@
return rc;
set_fmt_fail:
- kfree(sp->vb2_q.drv_priv);
+ kzfree(sp->vb2_q.drv_priv);
return rc;
}
@@ -445,7 +445,7 @@
v4l2_fh_exit(&sp->fh);
}
- kfree(sp);
+ kzfree(sp);
return 0;
}
@@ -479,7 +479,7 @@
{
struct camera_v4l2_private *sp = filep->private_data;
- kfree(sp->vb2_q.drv_priv);
+ kzfree(sp->vb2_q.drv_priv);
vb2_queue_release(&sp->vb2_q);
}
@@ -687,14 +687,14 @@
entity_fail:
media_device_unregister(v4l2_dev->mdev);
media_fail:
- kfree(v4l2_dev->mdev);
+ kzfree(v4l2_dev->mdev);
mdev_fail:
#endif
- kfree(v4l2_dev);
+ kzfree(v4l2_dev);
v4l2_fail:
video_device_release(pvdev->vdev);
video_fail:
- kfree(pvdev);
+ kzfree(pvdev);
init_end:
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 1d931df..5385d1e 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -88,8 +88,8 @@
{
.src = MSM_BUS_MASTER_VFE,
.dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 1027648000,
- .ib = 1105920000,
+ .ab = 2027648000U,
+ .ib = 2805920000U,
},
};
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index 6974cb4..f8cddb2 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -129,7 +129,7 @@
if (node->sd == q_node) { \
__q->len--; \
list_del_init(&node->member); \
- kfree(node); \
+ kzfree(node); \
break; \
} \
} \
@@ -146,7 +146,7 @@
if (node == q_node) { \
__q->len--; \
list_del_init(&node->member); \
- kfree(node); \
+ kzfree(node); \
break; \
} \
} \
@@ -165,7 +165,7 @@
if (node) { \
if (&node->member) \
list_del_init(&node->member); \
- kfree(node); \
+ kzfree(node); \
} \
} \
spin_unlock_irqrestore(&__q->lock, flags); \
@@ -288,14 +288,14 @@
list_del_init(&stream->list);
session->stream_q.len--;
- kfree(stream);
+ kzfree(stream);
}
static void msm_sd_unregister_subdev(struct video_device *vdev)
{
struct v4l2_subdev *sd = video_get_drvdata(vdev);
sd->devnode = NULL;
- kfree(vdev);
+ kzfree(vdev);
}
static inline int __msm_sd_register_subdev(struct v4l2_subdev *sd)
@@ -330,7 +330,7 @@
rc = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
sd->owner);
if (rc < 0) {
- kfree(vdev);
+ kzfree(vdev);
goto clean_up;
}
@@ -588,7 +588,7 @@
__msm_queue_find_command_ack_q,
&stream_id);
if (WARN_ON(!cmd_ack)) {
- kfree(ret_cmd);
+ kzfree(ret_cmd);
rc = -EFAULT;
break;
}
@@ -710,7 +710,7 @@
*event = cmd->event;
- kfree(cmd);
+ kzfree(cmd);
return rc;
}
@@ -1002,14 +1002,14 @@
entity_fail:
media_device_unregister(msm_v4l2_dev->mdev);
media_fail:
- kfree(msm_v4l2_dev->mdev);
+ kzfree(msm_v4l2_dev->mdev);
mdev_fail:
#endif
video_device_release(pvdev->vdev);
video_fail:
- kfree(pvdev);
+ kzfree(pvdev);
pvdev_fail:
- kfree(msm_v4l2_dev);
+ kzfree(msm_v4l2_dev);
probe_end:
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
index 22131f8..079dbb5 100644
--- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
+++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
@@ -77,7 +77,7 @@
static void msm_vb2_dma_contig_put_userptr(void *buf_priv)
{
- kfree(buf_priv);
+ kzfree(buf_priv);
}
static struct vb2_mem_ops msm_vb2_get_q_mem_op = {
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 637bce3..41234c3 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -293,6 +293,14 @@
goto vbif_remap_failed;
}
+ cpp_dev->cpp_hw_base = ioremap(cpp_dev->cpp_hw_mem->start,
+ resource_size(cpp_dev->cpp_hw_mem));
+ if (!cpp_dev->cpp_hw_base) {
+ rc = -ENOMEM;
+ pr_err("ioremap failed\n");
+ goto cpp_hw_remap_failed;
+ }
+
if (cpp_dev->state != CPP_STATE_BOOT) {
rc = request_irq(cpp_dev->irq->start, msm_cpp_irq,
IRQF_TRIGGER_RISING, "cpp", cpp_dev);
@@ -303,11 +311,19 @@
}
}
+ cpp_dev->hw_info.cpp_hw_version =
+ msm_camera_io_r(cpp_dev->cpp_hw_base);
+ pr_debug("CPP HW Version: 0x%x\n", cpp_dev->hw_info.cpp_hw_version);
+ cpp_dev->hw_info.cpp_hw_caps =
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4);
+ pr_debug("CPP HW Caps: 0x%x\n", cpp_dev->hw_info.cpp_hw_caps);
msm_camera_io_w(0x1, cpp_dev->vbif_base + 0x4);
if (cpp_dev->is_firmware_loaded == 1)
msm_cpp_boot_hw(cpp_dev);
return rc;
req_irq_fail:
+ iounmap(cpp_dev->cpp_hw_base);
+cpp_hw_remap_failed:
iounmap(cpp_dev->vbif_base);
vbif_remap_failed:
iounmap(cpp_dev->base);
@@ -327,6 +343,8 @@
free_irq(cpp_dev->irq->start, cpp_dev);
iounmap(cpp_dev->base);
+ iounmap(cpp_dev->vbif_base);
+ iounmap(cpp_dev->cpp_hw_base);
msm_cam_clk_enable(&cpp_dev->pdev->dev, cpp_clk_info,
cpp_dev->cpp_clk, ARRAY_SIZE(cpp_clk_info), 0);
if (0) {
@@ -336,15 +354,15 @@
}
}
-static void cpp_load_fw(struct cpp_device *cpp_dev)
+static void cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin)
{
uint32_t i;
uint32_t *ptr_bin = NULL;
int32_t rc = -EFAULT;
const struct firmware *fw = NULL;
- char *fw_name_bin = "cpp_firmware_v1_1_1.fw";
struct device *dev = &cpp_dev->pdev->dev;
+ pr_debug("%s: FW file: %s\n", __func__, fw_name_bin);
rc = request_firmware(&fw, fw_name_bin, dev);
if (rc) {
dev_err(dev, "Failed to locate blob %s from device %p, Error: %d\n",
@@ -690,14 +708,44 @@
struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
int rc = 0;
+ char *fw_name_bin;
mutex_lock(&cpp_dev->mutex);
CPP_DBG("E cmd: %d\n", cmd);
switch (cmd) {
+ case VIDIOC_MSM_CPP_GET_HW_INFO: {
+ if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
+ &cpp_dev->hw_info,
+ sizeof(struct cpp_hw_info))) {
+ mutex_unlock(&cpp_dev->mutex);
+ return -EINVAL;
+ }
+ break;
+ }
+
case VIDIOC_MSM_CPP_LOAD_FIRMWARE: {
if (cpp_dev->is_firmware_loaded == 0) {
+ fw_name_bin = kzalloc(ioctl_ptr->len, GFP_KERNEL);
+ if (!fw_name_bin) {
+ pr_err("%s:%d: malloc error\n", __func__,
+ __LINE__);
+ mutex_unlock(&cpp_dev->mutex);
+ return -EINVAL;
+ }
+
+ rc = (copy_from_user(fw_name_bin,
+ (void __user *)ioctl_ptr->ioctl_ptr,
+ ioctl_ptr->len) ? -EFAULT : 0);
+ if (rc) {
+ ERR_COPY_FROM_USER();
+ kfree(fw_name_bin);
+ mutex_unlock(&cpp_dev->mutex);
+ return -EINVAL;
+ }
+
disable_irq(cpp_dev->irq->start);
- cpp_load_fw(cpp_dev);
+ cpp_load_fw(cpp_dev, fw_name_bin);
+ kfree(fw_name_bin);
enable_irq(cpp_dev->irq->start);
cpp_dev->is_firmware_loaded = 1;
}
@@ -894,6 +942,14 @@
goto ERROR2;
}
+ cpp_dev->cpp_hw_mem = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "cpp_hw");
+ if (!cpp_dev->cpp_hw_mem) {
+ pr_err("no mem resource?\n");
+ rc = -ENODEV;
+ goto ERROR2;
+ }
+
cpp_dev->irq = platform_get_resource_byname(pdev,
IORESOURCE_IRQ, "cpp");
if (!cpp_dev->irq) {
@@ -999,6 +1055,10 @@
iommu_detach_device(cpp_dev->domain, cpp_dev->iommu_ctx);
msm_sd_unregister(&cpp_dev->msm_sd);
release_mem_region(cpp_dev->mem->start, resource_size(cpp_dev->mem));
+ release_mem_region(cpp_dev->vbif_mem->start,
+ resource_size(cpp_dev->vbif_mem));
+ release_mem_region(cpp_dev->cpp_hw_mem->start,
+ resource_size(cpp_dev->cpp_hw_mem));
mutex_destroy(&cpp_dev->mutex);
kfree(cpp_dev->cpp_clk);
kfree(cpp_dev);
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
index e8e37ed..0c586ca 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -125,8 +125,10 @@
struct resource *io;
struct resource *vbif_mem;
struct resource *vbif_io;
+ struct resource *cpp_hw_mem;
void __iomem *vbif_base;
void __iomem *base;
+ void __iomem *cpp_hw_base;
struct clk **cpp_clk;
struct regulator *fs_cpp;
struct mutex mutex;
@@ -141,6 +143,7 @@
struct cpp_subscribe_info cpp_subscribe_list[MAX_ACTIVE_CPP_INSTANCE];
uint32_t cpp_open_cnt;
+ struct cpp_hw_info hw_info;
struct msm_device_queue eventData_q; /* V4L2 Event Payload Queue */
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index 0641162..499b36c 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -95,6 +95,10 @@
static int mpq_sdmx_proc_limit = MAX_TS_PACKETS_FOR_SDMX_PROCESS;
module_param(mpq_sdmx_proc_limit, int, S_IRUGO | S_IWUSR);
+/* Debug flag for secure demux process */
+static int mpq_sdmx_debug;
+module_param(mpq_sdmx_debug, int, S_IRUGO | S_IWUSR);
+
/**
* Maximum allowed framing pattern size
@@ -4454,7 +4458,8 @@
{
struct sdmx_filter_status *sts;
struct mpq_feed *mpq_feed;
- u8 flags = 0; /* MPQ_TODO: EOS handling */
+ /* MPQ_TODO: EOS handling */
+ u8 flags = mpq_sdmx_debug ? SDMX_INPUT_FLAG_DBG_ENABLE : 0;
u32 errors;
u32 status;
u32 prev_read_offset;
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h
index 5b91436..f9d85aa 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h
+++ b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h
@@ -52,7 +52,8 @@
#define SDMX_INVALID_FILTER_HANDLE (-1)
/* Input flags */
-#define SDMX_INPUT_FLAG_EOS BIT(0)
+#define SDMX_INPUT_FLAG_EOS BIT(0)
+#define SDMX_INPUT_FLAG_DBG_ENABLE BIT(1)
enum sdmx_buf_mode {
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index f23c0aa..c8599d5 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -184,18 +184,12 @@
case HAL_BUFFER_OUTPUT:
buffer = HFI_BUFFER_OUTPUT;
break;
- case HAL_BUFFER_OUTPUT2:
- buffer = HFI_BUFFER_OUTPUT;
- break;
case HAL_BUFFER_EXTRADATA_INPUT:
buffer = HFI_BUFFER_EXTRADATA_INPUT;
break;
case HAL_BUFFER_EXTRADATA_OUTPUT:
buffer = HFI_BUFFER_EXTRADATA_OUTPUT;
break;
- case HAL_BUFFER_EXTRADATA_OUTPUT2:
- buffer = HFI_BUFFER_EXTRADATA_OUTPUT2;
- break;
case HAL_BUFFER_INTERNAL_SCRATCH:
buffer = HFI_BUFFER_INTERNAL_SCRATCH;
break;
diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c
index 5b5c121..b3bce5f 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.c
+++ b/drivers/media/platform/msm/vidc/msm_smem.c
@@ -19,43 +19,86 @@
struct smem_client {
int mem_type;
void *clnt;
+ struct msm_vidc_platform_resources *res;
};
-static int get_device_address(struct ion_client *clnt,
- struct ion_handle *hndl, int domain_num, int partition_num,
- unsigned long align, unsigned long *iova,
- unsigned long *buffer_size, int flags)
+static u32 get_tz_usage(struct smem_client *client, enum hal_buffer buffer_type)
+{
+ int i;
+ struct buffer_usage_set *buffer_usage_set;
+ struct buffer_usage_table *buffer_usage_tbl;
+
+ buffer_usage_set = &client->res->buffer_usage_set;
+ if (!buffer_usage_set) {
+ dprintk(VIDC_DBG, "no buffer usage set present!\n");
+ return 0;
+ }
+
+ for (i = 0; i < buffer_usage_set->count; i++) {
+ buffer_usage_tbl = &buffer_usage_set->buffer_usage_tbl[i];
+ if (buffer_usage_tbl->buffer_type & buffer_type)
+ return buffer_usage_tbl->tz_usage;
+ }
+ dprintk(VIDC_DBG, "No tz usage found for buffer type: %x\n",
+ buffer_type);
+ return 0;
+}
+
+static int get_device_address(struct smem_client *smem_client,
+ struct ion_handle *hndl, unsigned long align,
+ unsigned long *iova, unsigned long *buffer_size,
+ u32 flags, enum hal_buffer buffer_type)
{
int rc = 0;
- if (!iova || !buffer_size || !hndl || !clnt) {
+ int domain, partition;
+ struct ion_client *clnt = NULL;
+
+ if (!iova || !buffer_size || !hndl || !smem_client) {
dprintk(VIDC_ERR, "Invalid params: %p, %p, %p, %p\n",
- clnt, hndl, iova, buffer_size);
+ smem_client, hndl, iova, buffer_size);
return -EINVAL;
}
- dprintk(VIDC_DBG, "domain: %d, partition: %d\n",
- domain_num, partition_num);
+
+ clnt = smem_client->clnt;
+ if (!clnt) {
+ dprintk(VIDC_ERR, "Invalid client");
+ return -EINVAL;
+ }
+
+ rc = msm_smem_get_domain_partition(smem_client, flags, buffer_type,
+ &domain, &partition);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to get domain and partition: %d", rc);
+ goto mem_domain_get_failed;
+ }
+
if (flags & SMEM_SECURE) {
- if (flags & SMEM_INPUT)
- rc = msm_ion_secure_buffer(clnt, hndl, 0x1, 0);
- else
- rc = msm_ion_secure_buffer(clnt, hndl, 0x2, 0);
+ rc = msm_ion_secure_buffer(clnt, hndl,
+ get_tz_usage(smem_client, buffer_type), 0);
if (rc) {
dprintk(VIDC_ERR, "Failed to secure memory\n");
- goto mem_secure_failed;
+ goto mem_domain_get_failed;
}
}
- rc = ion_map_iommu(clnt, hndl, domain_num, partition_num, align,
+ rc = ion_map_iommu(clnt, hndl, domain, partition, align,
0, iova, buffer_size, 0, 0);
- if (rc)
+ if (rc) {
dprintk(VIDC_ERR,
"ion_map_iommu failed(%d).domain: %d,partition: %d\n",
- rc, domain_num, partition_num);
-mem_secure_failed:
+ rc, domain, partition);
+ goto mem_map_failed;
+ }
+
+ return 0;
+mem_map_failed:
+ if (flags & SMEM_SECURE)
+ msm_ion_unsecure_buffer(clnt, hndl);
+mem_domain_get_failed:
return rc;
}
static void put_device_address(struct ion_client *clnt,
- struct ion_handle *hndl, int domain_num, int partition_num, int flags)
+ struct ion_handle *hndl, int domain_num, int partition_num, u32 flags)
{
ion_unmap_iommu(clnt, hndl, domain_num, partition_num);
if (flags & SMEM_SECURE) {
@@ -64,9 +107,8 @@
}
}
-static int ion_user_to_kernel(struct smem_client *client,
- int fd, u32 offset, int domain, int partition,
- struct msm_smem *mem, int flags)
+static int ion_user_to_kernel(struct smem_client *client, int fd, u32 offset,
+ struct msm_smem *mem, enum hal_buffer buffer_type)
{
struct ion_handle *hndl;
unsigned long iova = 0;
@@ -74,6 +116,7 @@
unsigned long ionflags = 0;
int rc = 0;
int align = SZ_4K;
+
hndl = ion_import_dma_buf(client->clnt, fd);
if (IS_ERR_OR_NULL(hndl)) {
dprintk(VIDC_ERR, "Failed to get handle: %p, %d, %d, %p\n",
@@ -82,9 +125,6 @@
goto fail_import_fd;
}
mem->kvaddr = NULL;
- mem->domain = domain;
- mem->partition_num = partition;
- mem->flags = flags;
rc = ion_handle_get_flags(client->clnt, hndl, &ionflags);
if (rc) {
dprintk(VIDC_ERR, "Failed to get ion flags: %d\n", rc);
@@ -99,11 +139,14 @@
goto fail_map;
}
}
- if (flags & SMEM_SECURE)
+
+ mem->flags = ionflags;
+ mem->buffer_type = buffer_type;
+ if (mem->flags & SMEM_SECURE)
align = ALIGN(align, SZ_1M);
- rc = get_device_address(client->clnt, hndl, mem->domain,
- mem->partition_num, align, &iova, &buffer_size, flags);
+ rc = get_device_address(client, hndl, align, &iova, &buffer_size,
+ mem->flags, buffer_type);
if (rc) {
dprintk(VIDC_ERR, "Failed to get device address: %d\n", rc);
goto fail_device_address;
@@ -125,26 +168,20 @@
return rc;
}
-static int alloc_ion_mem(struct smem_client *client, size_t size,
- u32 align, u32 flags, int domain, int partition,
- struct msm_smem *mem, int map_kernel)
+static int alloc_ion_mem(struct smem_client *client, size_t size, u32 align,
+ u32 flags, enum hal_buffer buffer_type, struct msm_smem *mem,
+ int map_kernel)
{
struct ion_handle *hndl;
unsigned long iova = 0;
unsigned long buffer_size = 0;
- unsigned long ionflags = 0;
unsigned long heap_mask = 0;
int rc = 0;
- if (flags & SMEM_CACHED)
- ionflags = ION_SET_CACHED(ionflags);
- else
- ionflags = ION_SET_UNCACHED(ionflags);
align = ALIGN(align, SZ_4K);
size = ALIGN(size, SZ_4K);
if (flags & SMEM_SECURE) {
- ionflags |= ION_SECURE;
size = ALIGN(size, SZ_1M);
align = ALIGN(align, SZ_1M);
}
@@ -153,21 +190,18 @@
if (flags & SMEM_SECURE)
heap_mask = ION_HEAP(ION_CP_MM_HEAP_ID);
- dprintk(VIDC_DBG, "domain: %d, partition: %d\n",
- domain, partition);
- hndl = ion_alloc(client->clnt, size, align, heap_mask, ionflags);
+ hndl = ion_alloc(client->clnt, size, align, heap_mask, flags);
if (IS_ERR_OR_NULL(hndl)) {
dprintk(VIDC_ERR,
- "Failed to allocate shared memory = %p, %d, %d, 0x%lx\n",
- client, size, align, ionflags);
+ "Failed to allocate shared memory = %p, %d, %d, 0x%x\n",
+ client, size, align, flags);
rc = -ENOMEM;
goto fail_shared_mem_alloc;
}
mem->mem_type = client->mem_type;
mem->smem_priv = hndl;
- mem->domain = domain;
- mem->partition_num = partition;
mem->flags = flags;
+ mem->buffer_type = buffer_type;
if (map_kernel) {
mem->kvaddr = ion_map_kernel(client->clnt, hndl);
if (!mem->kvaddr) {
@@ -179,8 +213,8 @@
} else
mem->kvaddr = NULL;
- rc = get_device_address(client->clnt, hndl, mem->domain,
- mem->partition_num, align, &iova, &buffer_size, flags);
+ rc = get_device_address(client, hndl, align, &iova, &buffer_size,
+ flags, buffer_type);
if (rc) {
dprintk(VIDC_ERR, "Failed to get device address: %d\n",
rc);
@@ -202,10 +236,18 @@
static void free_ion_mem(struct smem_client *client, struct msm_smem *mem)
{
+ int domain, partition, rc;
+
+ rc = msm_smem_get_domain_partition((void *)client, mem->flags,
+ mem->buffer_type, &domain, &partition);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to get domain, partition: %d", rc);
+ return;
+ }
+
if (mem->device_addr)
put_device_address(client->clnt,
- mem->smem_priv, mem->domain,
- mem->partition_num, mem->flags);
+ mem->smem_priv, domain, partition, mem->flags);
if (mem->kvaddr)
ion_unmap_kernel(client->clnt, mem->smem_priv);
if (mem->smem_priv)
@@ -227,7 +269,7 @@
}
struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
- int domain, int partition, int flags)
+ enum hal_buffer buffer_type)
{
struct smem_client *client = clt;
int rc = 0;
@@ -243,8 +285,7 @@
}
switch (client->mem_type) {
case SMEM_ION:
- rc = ion_user_to_kernel(clt, fd, offset,
- domain, partition, mem, flags);
+ rc = ion_user_to_kernel(clt, fd, offset, mem, buffer_type);
break;
default:
dprintk(VIDC_ERR, "Mem type not supported\n");
@@ -337,7 +378,8 @@
return rc;
}
-void *msm_smem_new_client(enum smem_type mtype)
+void *msm_smem_new_client(enum smem_type mtype,
+ struct msm_vidc_platform_resources *res)
{
struct smem_client *client = NULL;
void *clnt = NULL;
@@ -354,6 +396,7 @@
if (client) {
client->mem_type = mtype;
client->clnt = clnt;
+ client->res = res;
}
} else {
dprintk(VIDC_ERR, "Failed to create new client: mtype = %d\n",
@@ -363,7 +406,7 @@
};
struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
- int domain, int partition, int map_kernel)
+ enum hal_buffer buffer_type, int map_kernel)
{
struct smem_client *client;
int rc = 0;
@@ -385,8 +428,8 @@
}
switch (client->mem_type) {
case SMEM_ION:
- rc = alloc_ion_mem(client, size, align, flags,
- domain, partition, mem, map_kernel);
+ rc = alloc_ion_mem(client, size, align, flags, buffer_type,
+ mem, map_kernel);
break;
default:
dprintk(VIDC_ERR, "Mem type not supported\n");
@@ -436,3 +479,36 @@
}
kfree(client);
}
+
+int msm_smem_get_domain_partition(void *clt, u32 flags, enum hal_buffer
+ buffer_type, int *domain_num, int *partition_num)
+{
+ struct smem_client *client = clt;
+ struct iommu_set *iommu_group_set = &client->res->iommu_group_set;
+ int i;
+ bool is_secure = (flags & SMEM_SECURE);
+ struct iommu_info *iommu_map;
+
+ *domain_num = -1;
+ *partition_num = -1;
+ if (!iommu_group_set) {
+ dprintk(VIDC_DBG, "no iommu group set present!\n");
+ return -ENOENT;
+ }
+
+ for (i = 0; i < iommu_group_set->count; i++) {
+ iommu_map = &iommu_group_set->iommu_maps[i];
+ if ((iommu_map->is_secure == is_secure) &&
+ (iommu_map->buffer_type & buffer_type)) {
+ *domain_num = iommu_map->domain;
+ *partition_num = 0;
+ if ((buffer_type & HAL_BUFFER_INTERNAL_CMD_QUEUE) &&
+ (iommu_map->npartitions == 2))
+ *partition_num = 1;
+ break;
+ }
+ }
+ dprintk(VIDC_DBG, "domain: %d, partition: %d found!\n",
+ *domain_num, *partition_num);
+ return 0;
+}
diff --git a/drivers/media/platform/msm/vidc/msm_smem.h b/drivers/media/platform/msm/vidc/msm_smem.h
index d1c8293..b80d63e 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.h
+++ b/drivers/media/platform/msm/vidc/msm_smem.h
@@ -15,15 +15,32 @@
#include <linux/types.h>
#include <linux/msm_ion.h>
+#include "msm_vidc_resources.h"
+
+#define HAL_BUFFER_MAX 0xb
enum smem_type {
SMEM_ION,
};
enum smem_prop {
- SMEM_CACHED = 0x1,
- SMEM_SECURE = 0x2,
- SMEM_INPUT = 0x4,
+ SMEM_CACHED = ION_FLAG_CACHED,
+ SMEM_SECURE = ION_SECURE,
+};
+
+enum hal_buffer {
+ HAL_BUFFER_INPUT = 0x1,
+ HAL_BUFFER_OUTPUT = 0x2,
+ HAL_BUFFER_OUTPUT2 = 0x2,
+ HAL_BUFFER_EXTRADATA_INPUT = 0x4,
+ HAL_BUFFER_EXTRADATA_OUTPUT = 0x8,
+ HAL_BUFFER_EXTRADATA_OUTPUT2 = 0x8,
+ HAL_BUFFER_INTERNAL_SCRATCH = 0x10,
+ HAL_BUFFER_INTERNAL_SCRATCH_1 = 0x20,
+ HAL_BUFFER_INTERNAL_SCRATCH_2 = 0x40,
+ HAL_BUFFER_INTERNAL_PERSIST = 0x80,
+ HAL_BUFFER_INTERNAL_PERSIST_1 = 0x100,
+ HAL_BUFFER_INTERNAL_CMD_QUEUE = 0x200,
};
struct msm_smem {
@@ -31,10 +48,9 @@
size_t size;
void *kvaddr;
unsigned long device_addr;
- int domain;
- int partition_num;
- int flags;
+ u32 flags;
void *smem_priv;
+ enum hal_buffer buffer_type;
};
enum smem_cache_ops {
@@ -43,14 +59,17 @@
SMEM_CACHE_CLEAN_INVALIDATE,
};
-
-void *msm_smem_new_client(enum smem_type mtype);
+void *msm_smem_new_client(enum smem_type mtype,
+ struct msm_vidc_platform_resources *res);
struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
- int domain, int partition, int map_kernel);
+ enum hal_buffer buffer_type, int map_kernel);
void msm_smem_free(void *clt, struct msm_smem *mem);
void msm_smem_delete_client(void *clt);
-struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset, int
- domain, int partition, int flags);
int msm_smem_cache_operations(void *clt, struct msm_smem *mem,
enum smem_cache_ops);
+struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
+ enum hal_buffer buffer_type);
+int msm_smem_clean_invalidate(void *clt, struct msm_smem *mem);
+int msm_smem_get_domain_partition(void *clt, u32 flags, enum hal_buffer
+ buffer_type, int *domain_num, int *partition_num);
#endif
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index 181b2b6..4f8c257 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -227,7 +227,7 @@
rc = -ENOMEM;
goto fail_nomem;
}
- v4l2_inst->mem_client = msm_smem_new_client(SMEM_ION);
+ v4l2_inst->mem_client = msm_smem_new_client(SMEM_ION, &core->resources);
if (!v4l2_inst->mem_client) {
dprintk(VIDC_ERR, "Failed to create memory client\n");
rc = -ENOMEM;
@@ -400,9 +400,8 @@
struct msm_v4l2_vid_inst *v4l2_inst;
int plane = 0;
int i, rc = 0;
- int smem_flags = 0;
- int domain;
struct hfi_device *hdev;
+ enum hal_buffer buffer_type;
vidc_inst = get_vidc_inst(file, fh);
v4l2_inst = get_v4l2_inst(file, fh);
@@ -432,7 +431,7 @@
goto exit;
}
for (i = 0; i < b->length; ++i) {
- smem_flags = 0;
+ buffer_type = HAL_BUFFER_OUTPUT;
if (EXTRADATA_IDX(b->length) &&
(i == EXTRADATA_IDX(b->length)) &&
!b->m.planes[i].length) {
@@ -449,18 +448,8 @@
kfree(binfo);
goto exit;
}
- if ((vidc_inst->mode == VIDC_SECURE)
- && (!EXTRADATA_IDX(b->length)
- || (i != EXTRADATA_IDX(b->length)))) {
- smem_flags |= SMEM_SECURE;
- domain = call_hfi_op(hdev, get_domain,
- hdev->hfi_device_data, CP_MAP);
- } else
- domain = call_hfi_op(hdev, get_domain,
- hdev->hfi_device_data, NS_MAP);
-
if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- smem_flags |= SMEM_INPUT;
+ buffer_type = HAL_BUFFER_INPUT;
temp = get_same_fd_buffer(&v4l2_inst->registered_bufs,
b->m.planes[i].reserved[0], &plane);
@@ -476,9 +465,9 @@
binfo->handle[i] = NULL;
} else {
handle = msm_smem_user_to_kernel(v4l2_inst->mem_client,
- b->m.planes[i].reserved[0],
- b->m.planes[i].reserved[1],
- domain, 0, smem_flags);
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1],
+ buffer_type);
if (!handle) {
dprintk(VIDC_ERR,
"Failed to get device buffer address\n");
@@ -796,13 +785,6 @@
res->load_freq_tbl = NULL;
}
-static inline void msm_vidc_free_iommu_maps(
- struct msm_vidc_platform_resources *res)
-{
- kfree(res->iommu_maps);
- res->iommu_maps = NULL;
-}
-
static inline void msm_vidc_free_reg_table(
struct msm_vidc_platform_resources *res)
{
@@ -828,6 +810,20 @@
}
}
+static inline void msm_vidc_free_iommu_groups(
+ struct msm_vidc_platform_resources *res)
+{
+ kfree(res->iommu_group_set.iommu_maps);
+ res->iommu_group_set.iommu_maps = NULL;
+}
+
+static inline void msm_vidc_free_buffer_usage_table(
+ struct msm_vidc_platform_resources *res)
+{
+ kfree(res->buffer_usage_set.buffer_usage_tbl);
+ res->buffer_usage_set.buffer_usage_tbl = NULL;
+}
+
static int msm_vidc_load_freq_table(struct msm_vidc_platform_resources *res)
{
int rc = 0;
@@ -861,60 +857,6 @@
return rc;
}
-static int msm_vidc_load_iommu_maps(struct msm_vidc_platform_resources *res)
-{
- int rc = 0;
- int num_elements = 0;
- int i;
- struct platform_device *pdev = res->pdev;
- char *names[MAX_MAP] = {
- [CP_MAP] = "qcom,vidc-cp-map",
- [NS_MAP] = "qcom,vidc-ns-map",
- };
- char *contexts[MAX_MAP] = {
- [CP_MAP] = "venus_cp",
- [NS_MAP] = "venus_ns",
- };
-
-
- res->iommu_maps = kzalloc(MAX_MAP * sizeof(*res->iommu_maps),
- GFP_KERNEL);
- if (!res->iommu_maps) {
- dprintk(VIDC_ERR, "%s Failed to alloc iommu_maps\n", __func__);
- return -ENOMEM;
- }
-
- res->iommu_maps_size = MAX_MAP;
- for (i = 0; i < MAX_MAP; i++) {
- num_elements = get_u32_array_num_elements(pdev, names[i]);
- if ((num_elements == 0)) {
- if (i == NS_MAP) {
- dprintk(VIDC_ERR,
- "Domain not found in dtsi file :%s\n",
- names[i]);
- goto error;
- } else
- continue;
- }
- memcpy(&res->iommu_maps[i].name, names[i],
- strlen(names[i]));
- memcpy(&res->iommu_maps[i].ctx, contexts[i],
- strlen(contexts[i]));
-
- if (of_property_read_u32_array(pdev->dev.of_node, names[i],
- res->iommu_maps[i].addr_range, num_elements * 2)) {
- dprintk(VIDC_ERR, "Failed to read iommu map :%s\n",
- names[i]);
- rc = -EINVAL;
- goto error;
- }
- }
- return rc;
-error:
- msm_vidc_free_iommu_maps(res);
- return rc;
-}
-
static int msm_vidc_load_reg_table(struct msm_vidc_platform_resources *res)
{
struct reg_set *reg_set;
@@ -932,7 +874,7 @@
reg_set->reg_tbl = kzalloc(reg_set->count *
sizeof(*(reg_set->reg_tbl)), GFP_KERNEL);
if (!reg_set->reg_tbl) {
- dprintk(VIDC_ERR, "%s Failed to alloc temp\n",
+ dprintk(VIDC_ERR, "%s Failed to alloc register table\n",
__func__);
return -ENOMEM;
}
@@ -1091,6 +1033,153 @@
return rc;
}
+static int msm_vidc_load_iommu_groups(struct msm_vidc_platform_resources *res)
+{
+ int rc = 0;
+ struct platform_device *pdev = res->pdev;
+ struct device_node *ctx_node;
+ struct iommu_set *iommu_group_set = &res->iommu_group_set;
+ int array_size;
+ int i;
+ struct iommu_info *iommu_map;
+ u32 *buffer_types = NULL;
+
+ if (!of_get_property(pdev->dev.of_node, "qcom,iommu-groups",
+ &array_size)) {
+ dprintk(VIDC_ERR, "Could not find iommu_groups property\n");
+ iommu_group_set->count = 0;
+ rc = -ENOENT;
+ goto err_no_of_node;
+ }
+
+ iommu_group_set->count = array_size / sizeof(u32);
+ if (iommu_group_set->count == 0) {
+ dprintk(VIDC_ERR, "No group present in iommu_groups\n");
+ rc = -ENOENT;
+ goto err_no_of_node;
+ }
+
+ iommu_group_set->iommu_maps = kzalloc(iommu_group_set->count *
+ sizeof(*(iommu_group_set->iommu_maps)), GFP_KERNEL);
+ if (!iommu_group_set->iommu_maps) {
+ dprintk(VIDC_ERR, "%s Failed to alloc iommu_maps\n",
+ __func__);
+ rc = -ENOMEM;
+ goto err_no_of_node;
+ }
+
+ buffer_types = kzalloc(iommu_group_set->count * sizeof(*buffer_types),
+ GFP_KERNEL);
+ if (!buffer_types) {
+ dprintk(VIDC_ERR,
+ "%s Failed to alloc iommu group buffer types\n",
+ __func__);
+ rc = -ENOMEM;
+ goto err_load_groups;
+ }
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,iommu-group-buffer-types", buffer_types,
+ iommu_group_set->count);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s Failed to read iommu group buffer types\n", __func__);
+ goto err_load_groups;
+ }
+
+ for (i = 0; i < iommu_group_set->count; i++) {
+ iommu_map = &iommu_group_set->iommu_maps[i];
+ ctx_node = of_parse_phandle(pdev->dev.of_node,
+ "qcom,iommu-groups", i);
+ if (!ctx_node) {
+ dprintk(VIDC_ERR, "Unable to parse phandle : %u\n", i);
+ rc = -EBADHANDLE;
+ goto err_load_groups;
+ }
+
+ rc = of_property_read_string(ctx_node, "label",
+ &(iommu_map->name));
+ if (rc) {
+ dprintk(VIDC_ERR, "Could not find label property\n");
+ goto err_load_groups;
+ }
+
+ if (!of_get_property(ctx_node, "qcom,virtual-addr-pool",
+ &array_size)) {
+ dprintk(VIDC_ERR,
+ "Could not find any addr pool for group : %s\n",
+ iommu_map->name);
+ rc = -EBADHANDLE;
+ goto err_load_groups;
+ }
+
+ iommu_map->npartitions = array_size / sizeof(u32) / 2;
+
+ rc = of_property_read_u32_array(ctx_node,
+ "qcom,virtual-addr-pool",
+ (u32 *)iommu_map->addr_range,
+ iommu_map->npartitions * 2);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Could not read addr pool for group : %s\n",
+ iommu_map->name);
+ goto err_load_groups;
+ }
+
+ iommu_map->buffer_type = buffer_types[i];
+ iommu_map->is_secure =
+ of_property_read_bool(ctx_node, "qcom,secure-domain");
+ }
+ kfree(buffer_types);
+ return 0;
+err_load_groups:
+ kfree(buffer_types);
+ msm_vidc_free_iommu_groups(res);
+err_no_of_node:
+ return rc;
+}
+
+static int msm_vidc_load_buffer_usage_table(
+ struct msm_vidc_platform_resources *res)
+{
+ int rc = 0;
+ struct platform_device *pdev = res->pdev;
+ struct buffer_usage_set *buffer_usage_set = &res->buffer_usage_set;
+
+ buffer_usage_set->count = get_u32_array_num_elements(
+ pdev, "qcom,buffer-type-tz-usage-table");
+ if (buffer_usage_set->count == 0) {
+ dprintk(VIDC_DBG, "no elements in buffer usage set\n");
+ return 0;
+ }
+
+ buffer_usage_set->buffer_usage_tbl = kzalloc(buffer_usage_set->count *
+ sizeof(*(buffer_usage_set->buffer_usage_tbl)),
+ GFP_KERNEL);
+ if (!buffer_usage_set->buffer_usage_tbl) {
+ dprintk(VIDC_ERR, "%s Failed to alloc buffer usage table\n",
+ __func__);
+ rc = -ENOMEM;
+ goto err_load_buf_usage;
+ }
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,buffer-type-tz-usage-table",
+ (u32 *)buffer_usage_set->buffer_usage_tbl,
+ buffer_usage_set->count *
+ (sizeof(*buffer_usage_set->buffer_usage_tbl)/sizeof(u32)));
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to read buffer usage table\n");
+ goto err_load_buf_usage;
+ }
+
+ return 0;
+err_load_buf_usage:
+ msm_vidc_free_buffer_usage_table(res);
+ return rc;
+}
+
+
static int read_platform_resources_from_dt(
struct msm_vidc_platform_resources *res)
{
@@ -1117,29 +1206,36 @@
dprintk(VIDC_ERR, "Failed to load freq table: %d\n", rc);
goto err_load_freq_table;
}
- rc = msm_vidc_load_iommu_maps(res);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to load iommu maps: %d\n", rc);
- goto err_load_iommu_maps;
- }
rc = msm_vidc_load_reg_table(res);
if (rc) {
dprintk(VIDC_ERR, "Failed to load reg table: %d\n", rc);
goto err_load_reg_table;
}
-
rc = msm_vidc_load_bus_vectors(res);
if (rc) {
dprintk(VIDC_ERR, "Failed to load bus vectors: %d\n", rc);
goto err_load_bus_vectors;
}
+ rc = msm_vidc_load_iommu_groups(res);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to load iommu groups: %d\n", rc);
+ goto err_load_iommu_groups;
+ }
+ rc = msm_vidc_load_buffer_usage_table(res);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to load buffer usage table: %d\n", rc);
+ goto err_load_buffer_usage_table;
+ }
return rc;
+err_load_buffer_usage_table:
+ msm_vidc_free_iommu_groups(res);
+err_load_iommu_groups:
+ msm_vidc_free_bus_vectors(res);
err_load_bus_vectors:
msm_vidc_free_reg_table(res);
err_load_reg_table:
- msm_vidc_free_iommu_maps(res);
-err_load_iommu_maps:
msm_vidc_free_freq_table(res);
err_load_freq_table:
return rc;
@@ -1151,7 +1247,6 @@
struct resource *kres = NULL;
struct platform_device *pdev = res->pdev;
struct msm_vidc_v4l2_platform_data *pdata = pdev->dev.platform_data;
- int64_t start, size;
int c = 0, rc = 0;
if (!pdata) {
@@ -1182,33 +1277,6 @@
res->load_freq_tbl[c].load = pdata->load_table[c][0];
res->load_freq_tbl[c].freq = pdata->load_table[c][1];
}
-
- res->iommu_maps = kzalloc(MAX_MAP *
- sizeof(*res->iommu_maps), GFP_KERNEL);
- if (!res->iommu_maps) {
- dprintk(VIDC_ERR, "%s Failed to alloc iommu_maps\n",
- __func__);
- kfree(res->load_freq_tbl);
- return -ENOMEM;
- }
-
- res->iommu_maps_size = MAX_MAP;
-
- start = pdata->iommu_table[MSM_VIDC_V4L2_IOMMU_MAP_CP][0];
- size = pdata->iommu_table[MSM_VIDC_V4L2_IOMMU_MAP_CP][1];
- res->iommu_maps[CP_MAP] = (struct msm_vidc_iommu_info) {
- .addr_range = {(u32) start, (u32) size},
- .name = "qcom,vidc-cp-map",
- .ctx = "venus_cp",
- };
-
- start = pdata->iommu_table[MSM_VIDC_V4L2_IOMMU_MAP_NS][0];
- size = pdata->iommu_table[MSM_VIDC_V4L2_IOMMU_MAP_NS][1];
- res->iommu_maps[NS_MAP] = (struct msm_vidc_iommu_info) {
- .addr_range = {(u32) start, (u32) size},
- .name = "qcom,vidc-ns-map",
- .ctx = "venus_ns",
- };
return rc;
}
@@ -1365,9 +1433,10 @@
v4l2_device_unregister(&core->v4l2_dev);
msm_vidc_free_freq_table(&core->resources);
- msm_vidc_free_iommu_maps(&core->resources);
msm_vidc_free_reg_table(&core->resources);
msm_vidc_free_bus_vectors(&core->resources);
+ msm_vidc_free_iommu_groups(&core->resources);
+ msm_vidc_free_buffer_usage_table(&core->resources);
kfree(core);
return rc;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index ae98afb..5966d12 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -584,6 +584,7 @@
int rc = 0;
int ret;
int i;
+ struct hal_buffer_requirements *buff_req_buffer;
if (!inst || !f || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR,
"Invalid input, inst = %p, format = %p\n", inst, f);
@@ -636,12 +637,26 @@
dprintk(VIDC_WARN,
"Color format not recognized\n");
}
- f->fmt.pix_mp.plane_fmt[0].sizeimage =
- inst->buff_req.buffer[HAL_BUFFER_OUTPUT].buffer_size;
+ buff_req_buffer =
+ get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+ if (buff_req_buffer)
+ f->fmt.pix_mp.plane_fmt[0].sizeimage =
+ buff_req_buffer->buffer_size;
+ else
+ f->fmt.pix_mp.plane_fmt[0].sizeimage = 0;
+
extra_idx = EXTRADATA_IDX(fmt->num_planes);
if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
- f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
- inst->buff_req.buffer[HAL_BUFFER_EXTRADATA_OUTPUT].buffer_size;
+ buff_req_buffer =
+ get_buff_req_buffer(inst,
+ HAL_BUFFER_EXTRADATA_OUTPUT);
+ if (buff_req_buffer)
+ f->fmt.pix_mp.plane_fmt[extra_idx].
+ sizeimage =
+ buff_req_buffer->buffer_size;
+ else
+ f->fmt.pix_mp.plane_fmt[extra_idx].
+ sizeimage = 0;
}
for (i = 0; i < fmt->num_planes; ++i)
inst->bufq[CAPTURE_PORT].
@@ -708,6 +723,7 @@
int rc = 0;
int ret = 0;
int i;
+ struct hal_buffer_requirements *buff_req_buffer;
if (!inst || !f) {
dprintk(VIDC_ERR,
"Invalid input, inst = %p, format = %p\n", inst, f);
@@ -743,12 +759,24 @@
f->fmt.pix_mp.width);
}
} else {
- f->fmt.pix_mp.plane_fmt[0].sizeimage =
- inst->buff_req.buffer[HAL_BUFFER_OUTPUT].buffer_size;
+ buff_req_buffer =
+ get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+ if (buff_req_buffer)
+ f->fmt.pix_mp.plane_fmt[0].sizeimage =
+ buff_req_buffer->buffer_size;
+ else
+ f->fmt.pix_mp.plane_fmt[0].sizeimage = 0;
extra_idx = EXTRADATA_IDX(fmt->num_planes);
if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
- f->fmt.pix_mp.plane_fmt[1].sizeimage =
- inst->buff_req.buffer[HAL_BUFFER_EXTRADATA_OUTPUT].buffer_size;
+ buff_req_buffer =
+ get_buff_req_buffer(inst,
+ HAL_BUFFER_EXTRADATA_OUTPUT);
+ if (buff_req_buffer)
+ f->fmt.pix_mp.plane_fmt[1].sizeimage =
+ buff_req_buffer->buffer_size;
+ else
+ f->fmt.pix_mp.plane_fmt[1].sizeimage =
+ 0;
}
}
f->fmt.pix_mp.num_planes = fmt->num_planes;
@@ -893,9 +921,16 @@
break;
}
mutex_lock(&inst->lock);
+ bufreq = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+ if (!bufreq) {
+ dprintk(VIDC_ERR,
+ "No buffer requirement for buffer type %x\n",
+ HAL_BUFFER_OUTPUT);
+ rc = -EINVAL;
+ break;
+ }
if (*num_buffers && *num_buffers >
- inst->buff_req.buffer[HAL_BUFFER_OUTPUT].
- buffer_count_actual) {
+ bufreq->buffer_count_actual) {
struct hal_buffer_count_actual new_buf_count;
enum hal_property property_id =
HAL_PARAM_BUFFER_COUNT_ACTUAL;
@@ -906,22 +941,25 @@
inst->session, property_id, &new_buf_count);
}
- bufreq = &inst->buff_req.buffer[HAL_BUFFER_OUTPUT];
if (bufreq->buffer_count_actual > *num_buffers)
*num_buffers = bufreq->buffer_count_actual;
else
- bufreq->buffer_count_actual = *num_buffers ;
+ bufreq->buffer_count_actual = *num_buffers;
mutex_unlock(&inst->lock);
dprintk(VIDC_DBG, "count = %d, size = %d, alignment = %d\n",
inst->buff_req.buffer[1].buffer_count_actual,
inst->buff_req.buffer[1].buffer_size,
inst->buff_req.buffer[1].buffer_alignment);
- sizes[0] = inst->buff_req.buffer[HAL_BUFFER_OUTPUT].buffer_size;
+ sizes[0] = bufreq->buffer_size;
extra_idx =
EXTRADATA_IDX(inst->fmts[CAPTURE_PORT]->num_planes);
if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
- sizes[extra_idx] =
- inst->buff_req.buffer[HAL_BUFFER_EXTRADATA_OUTPUT].buffer_size;
+ bufreq = get_buff_req_buffer(inst,
+ HAL_BUFFER_EXTRADATA_OUTPUT);
+ if (bufreq)
+ sizes[extra_idx] = bufreq->buffer_size;
+ else
+ sizes[extra_idx] = 0;
}
break;
default:
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 042900e..218987e 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -82,18 +82,16 @@
return rc;
}
-int msm_vidc_get_iommu_maps(void *instance,
- struct msm_vidc_iommu_info maps[MAX_MAP])
+int msm_vidc_get_iommu_domain_partition(void *instance, u32 flags,
+ enum v4l2_buf_type buf_type, int *domain, int *partition)
{
struct msm_vidc_inst *inst = instance;
- struct hfi_device *hdev;
- if (!inst || !maps || !inst->core || !inst->core->device)
+ if (!inst || !inst->core || !inst->core->device)
return -EINVAL;
- hdev = inst->core->device;
-
- return call_hfi_op(hdev, iommu_get_map, hdev->hfi_device_data, maps);
+ return msm_comm_get_domain_partition(inst, flags, buf_type, domain,
+ partition);
}
int msm_vidc_querycap(void *instance, struct v4l2_capability *cap)
@@ -436,7 +434,8 @@
i <= SESSION_MSG_INDEX(SESSION_MSG_END); i++) {
init_completion(&inst->completions[i]);
}
- inst->mem_client = msm_smem_new_client(SMEM_ION);
+ inst->mem_client = msm_smem_new_client(SMEM_ION,
+ &inst->core->resources);
if (!inst->mem_client) {
dprintk(VIDC_ERR, "Failed to create memory client\n");
goto fail_mem_client;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 8cce310..e55c0f1 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -193,7 +193,7 @@
}
struct buf_queue *msm_comm_get_vb2q(
- struct msm_vidc_inst *inst, enum v4l2_buf_type type)
+ struct msm_vidc_inst *inst, enum v4l2_buf_type type)
{
if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
return &inst->bufq[CAPTURE_PORT];
@@ -417,7 +417,7 @@
memcpy(&inst->buff_req, response->data,
sizeof(struct buffer_requirements));
mutex_unlock(&inst->lock);
- for (i = 0; i < 8; i++) {
+ for (i = 0; i < HAL_BUFFER_MAX; i++) {
dprintk(VIDC_DBG,
"buffer type: %d, count : %d, size: %d\n",
inst->buff_req.buffer[i].buffer_type,
@@ -1123,8 +1123,8 @@
}
mutex_lock(&core->lock);
core->state = VIDC_CORE_UNINIT;
- call_hfi_op(hdev, unload_fw, hdev->hfi_device_data);
mutex_unlock(&core->lock);
+ call_hfi_op(hdev, unload_fw, hdev->hfi_device_data);
msm_comm_unvote_buses(core, DDR_MEM|OCMEM_MEM);
}
core_already_uninited:
@@ -1462,7 +1462,6 @@
struct internal_buf *binfo;
struct vidc_buffer_addr_info buffer_info;
u32 smem_flags = 0;
- int domain;
struct hal_buffer_requirements *scratch_buf;
int i;
struct hfi_device *hdev;
@@ -1481,20 +1480,15 @@
scratch_buf->buffer_count_actual,
scratch_buf->buffer_size);
- if (inst->mode == VIDC_SECURE) {
- domain = call_hfi_op(hdev, get_domain,
- hdev->hfi_device_data, CP_MAP);
+ if (inst->mode == VIDC_SECURE)
smem_flags |= SMEM_SECURE;
- } else
- domain = call_hfi_op(hdev, get_domain,
- hdev->hfi_device_data, NS_MAP);
if (scratch_buf->buffer_size) {
for (i = 0; i < scratch_buf->buffer_count_actual;
i++) {
handle = msm_smem_alloc(inst->mem_client,
scratch_buf->buffer_size, 1, smem_flags,
- domain, 0, 0);
+ buffer_type, 0);
if (!handle) {
dprintk(VIDC_ERR,
"Failed to allocate scratch memory\n");
@@ -1550,7 +1544,6 @@
struct internal_buf *binfo;
struct vidc_buffer_addr_info buffer_info;
u32 smem_flags = 0;
- int domain;
struct hal_buffer_requirements *persist_buf;
int i;
struct hfi_device *hdev;
@@ -1575,19 +1568,14 @@
return rc;
}
- if (inst->mode == VIDC_SECURE) {
- domain = call_hfi_op(hdev, get_domain,
- hdev->hfi_device_data, CP_MAP);
+ if (inst->mode == VIDC_SECURE)
smem_flags |= SMEM_SECURE;
- } else
- domain = call_hfi_op(hdev, get_domain,
- hdev->hfi_device_data, NS_MAP);
if (persist_buf->buffer_size) {
for (i = 0; i < persist_buf->buffer_count_actual; i++) {
handle = msm_smem_alloc(inst->mem_client,
persist_buf->buffer_size, 1, smem_flags,
- domain, 0, 0);
+ buffer_type, 0);
if (!handle) {
dprintk(VIDC_ERR,
"Failed to allocate persist memory\n");
@@ -2310,6 +2298,41 @@
return ret;
};
+int msm_comm_get_domain_partition(struct msm_vidc_inst *inst, u32 flags,
+ enum v4l2_buf_type buf_type, int *domain, int *partition)
+{
+ struct hfi_device *hdev;
+ u32 hal_buffer_type = 0;
+ if (!inst || !inst->core || !inst->core->device)
+ return -EINVAL;
+
+ hdev = inst->core->device;
+
+ /*
+ * TODO: Due to the way in which the underlying smem mechanism
+ * maps buffer types to corresponding IOMMU domains, we need to
+ * pass in HAL_BUFFER_OUTPUT for input buffers (and vice versa)
+ * so that buffers are mapped into the correct domains. In the
+ * future, we should try to remove this workaround.
+ */
+ switch (buf_type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ hal_buffer_type = (inst->session_type == MSM_VIDC_ENCODER) ?
+ HAL_BUFFER_INPUT : HAL_BUFFER_OUTPUT;
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ hal_buffer_type = (inst->session_type == MSM_VIDC_ENCODER) ?
+ HAL_BUFFER_OUTPUT : HAL_BUFFER_INPUT;
+ break;
+ default:
+ dprintk(VIDC_ERR, "v4l2 buf type not found %d\n", buf_type);
+ return -ENOTSUPP;
+ }
+ return call_hfi_op(hdev, iommu_get_domain_partition,
+ hdev->hfi_device_data, flags, hal_buffer_type, domain,
+ partition);
+};
+
int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
enum hal_ssr_trigger_type type)
{
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index 69f41c7..4f3deb6 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -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
@@ -39,6 +39,10 @@
int msm_comm_force_cleanup(struct msm_vidc_inst *inst);
enum hal_extradata_id msm_comm_get_hal_extradata_index(
enum v4l2_mpeg_vidc_extradata index);
+int msm_comm_get_domain_partition(struct msm_vidc_inst *inst, u32 flags,
+ enum v4l2_buf_type buf_type, int *domain, int *partition);
+struct hal_buffer_requirements *get_buff_req_buffer(
+ struct msm_vidc_inst *inst, u32 buffer_type);
#define IS_PRIV_CTRL(idx) (\
(V4L2_CTRL_ID2CLASS(idx) == V4L2_CTRL_CLASS_MPEG) && \
V4L2_CTRL_DRIVER_PRIV(idx))
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
index 8fc6452..54c0878 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
@@ -32,6 +32,36 @@
int count;
};
+struct addr_range {
+ u32 start;
+ u32 size;
+};
+
+struct iommu_info {
+ const char *name;
+ u32 buffer_type;
+ struct iommu_group *group;
+ int domain;
+ bool is_secure;
+ struct addr_range addr_range[2];
+ int npartitions;
+};
+
+struct iommu_set {
+ struct iommu_info *iommu_maps;
+ u32 count;
+};
+
+struct buffer_usage_table {
+ u32 buffer_type;
+ u32 tz_usage;
+};
+
+struct buffer_usage_set {
+ struct buffer_usage_table *buffer_usage_tbl;
+ u32 count;
+};
+
struct msm_vidc_platform_resources {
uint32_t fw_base_addr;
uint32_t register_base;
@@ -39,10 +69,10 @@
uint32_t irq;
struct load_freq_table *load_freq_tbl;
uint32_t load_freq_tbl_size;
- struct msm_vidc_iommu_info *iommu_maps;
- uint32_t iommu_maps_size;
struct reg_set reg_set;
struct msm_bus_scale_pdata *bus_pdata;
+ struct iommu_set iommu_group_set;
+ struct buffer_usage_set buffer_usage_set;
struct platform_device *pdev;
};
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index 25cc239..88dc4fe 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -1113,25 +1113,14 @@
return 0;
}
-static int q6_hfi_get_domain(void *dev, enum msm_vidc_io_maps iomap)
+static int q6_hfi_iommu_get_domain_partition(void *dev, u32 flags,
+ u32 buffer_type, int *domain, int *partition)
{
(void)dev;
- (void)iomap;
dprintk(VIDC_ERR, "Not implemented: %s", __func__);
- return 0;
-}
-
-static int q6_hfi_iommu_get_map(void *dev,
- struct msm_vidc_iommu_info maps[MAX_MAP])
-{
- (void)dev;
- (void)maps;
-
- dprintk(VIDC_ERR, "Not implemented: %s", __func__);
-
- return 0;
+ return -ENOTSUPP;
}
static int q6_hfi_iommu_attach(void *dev)
@@ -1230,8 +1219,7 @@
hdev->alloc_ocmem = q6_hfi_alloc_ocmem;
hdev->free_ocmem = q6_hfi_free_ocmem;
hdev->is_ocmem_present = q6_hfi_is_ocmem_present;
- hdev->get_domain = q6_hfi_get_domain;
- hdev->iommu_get_map = q6_hfi_iommu_get_map;
+ hdev->iommu_get_domain_partition = q6_hfi_iommu_get_domain_partition;
hdev->load_fw = q6_hfi_load_fw;
hdev->unload_fw = q6_hfi_unload_fw;
hdev->get_fw_info = q6_hfi_get_fw_info;
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index af8b761..8c30b6c 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -333,7 +333,7 @@
}
static int venus_hfi_alloc(void *mem, void *clnt, u32 size, u32 align,
- u32 flags, int domain)
+ u32 flags, u32 usage)
{
struct vidc_mem_addr *vmem;
struct msm_smem *alloc;
@@ -346,7 +346,7 @@
vmem = (struct vidc_mem_addr *)mem;
dprintk(VIDC_INFO, "start to alloc: size:%d, Flags: %d", size, flags);
- alloc = msm_smem_alloc(clnt, size, align, flags, domain, 1, 1);
+ alloc = msm_smem_alloc(clnt, size, align, flags, usage, 1);
dprintk(VIDC_DBG, "Alloc done");
if (!alloc) {
dprintk(VIDC_ERR, "Alloc failed\n");
@@ -632,6 +632,7 @@
struct hfi_mem_map_table *qdss;
struct hfi_mem_map *mem_map;
int num_entries = sizeof(venus_qdss_entries)/(2 * sizeof(u32));
+ int domain, partition;
if (device->qdss.mem_data) {
qdss = (struct hfi_mem_map_table *)
@@ -641,11 +642,12 @@
(u32 *)((u32)device->qdss.align_device_addr +
sizeof(struct hfi_mem_map_table));
mem_map = (struct hfi_mem_map *)(qdss + 1);
+ msm_smem_get_domain_partition(device->hal_client, 0,
+ HAL_BUFFER_INTERNAL_CMD_QUEUE, &domain, &partition);
for (i = 0; i < num_entries; i++) {
msm_iommu_unmap_contig_buffer(
(unsigned long)(mem_map[i].virtual_addr),
- device->resources.io_map[NS_MAP].domain,
- 1, SZ_4K);
+ domain, partition, SZ_4K);
}
venus_hfi_free(device->hal_client, device->qdss.mem_data);
}
@@ -674,7 +676,7 @@
device->hal_client = NULL;
}
static int venus_hfi_get_qdss_iommu_virtual_addr(struct hfi_mem_map *mem_map,
- int domain)
+ int domain, int partition)
{
int i;
int rc = 0;
@@ -703,14 +705,13 @@
for (--i; i >= 0; i--) {
msm_iommu_unmap_contig_buffer(
(unsigned long)(mem_map[i].virtual_addr),
- domain, 1, SZ_4K);
+ domain, partition, SZ_4K);
}
}
return rc;
}
-static int venus_hfi_interface_queues_init(struct venus_hfi_device *dev,
- int domain)
+static int venus_hfi_interface_queues_init(struct venus_hfi_device *dev)
{
struct hfi_queue_table_header *q_tbl_hdr;
struct hfi_queue_header *q_hdr;
@@ -723,10 +724,11 @@
struct vidc_mem_addr *mem_addr;
int offset = 0;
int num_entries = sizeof(venus_qdss_entries)/(2 * sizeof(u32));
+ int domain, partition;
mem_addr = &dev->mem_addr;
rc = venus_hfi_alloc((void *) mem_addr,
- dev->hal_client, QUEUE_SIZE, 1,
- 0, domain);
+ dev->hal_client, QUEUE_SIZE, 1, 0,
+ HAL_BUFFER_INTERNAL_CMD_QUEUE);
if (rc) {
dprintk(VIDC_ERR, "iface_q_table_alloc_fail");
goto fail_alloc_queue;
@@ -752,8 +754,8 @@
}
rc = venus_hfi_alloc((void *) mem_addr,
- dev->hal_client, QDSS_SIZE, 1,
- 0, domain);
+ dev->hal_client, QDSS_SIZE, 1, 0,
+ HAL_BUFFER_INTERNAL_CMD_QUEUE);
if (rc) {
dprintk(VIDC_WARN,
"qdss_alloc_fail: QDSS messages logging will not work");
@@ -765,8 +767,8 @@
dev->qdss.mem_data = mem_addr->mem_data;
}
rc = venus_hfi_alloc((void *) mem_addr,
- dev->hal_client, SFR_SIZE, 1,
- 0, domain);
+ dev->hal_client, SFR_SIZE, 1, 0,
+ HAL_BUFFER_INTERNAL_CMD_QUEUE);
if (rc) {
dprintk(VIDC_WARN, "sfr_alloc_fail: SFR not will work");
dev->sfr.align_device_addr = NULL;
@@ -824,7 +826,9 @@
(u32 *) ((u32)dev->qdss.align_device_addr +
sizeof(struct hfi_mem_map_table));
mem_map = (struct hfi_mem_map *)(qdss + 1);
- rc = venus_hfi_get_qdss_iommu_virtual_addr(mem_map, domain);
+ msm_smem_get_domain_partition(dev->hal_client, 0,
+ HAL_BUFFER_INTERNAL_CMD_QUEUE, &domain, &partition);
+ rc = venus_hfi_get_qdss_iommu_virtual_addr(mem_map, domain, partition);
if (rc) {
dprintk(VIDC_ERR,
"IOMMU mapping failed, Freeing qdss memdata");
@@ -940,7 +944,7 @@
venus_hfi_set_registers(dev);
if (!dev->hal_client) {
- dev->hal_client = msm_smem_new_client(SMEM_ION);
+ dev->hal_client = msm_smem_new_client(SMEM_ION, dev->res);
if (dev->hal_client == NULL) {
dprintk(VIDC_ERR, "Failed to alloc ION_Client");
rc = -ENODEV;
@@ -951,8 +955,7 @@
dev->hal_data->device_base_addr,
(u32) dev->hal_data->register_base_addr);
- rc = venus_hfi_interface_queues_init(dev,
- dev->resources.io_map[NS_MAP].domain);
+ rc = venus_hfi_interface_queues_init(dev);
if (rc) {
dprintk(VIDC_ERR, "failed to init queues");
rc = -ENOMEM;
@@ -2038,68 +2041,69 @@
static int venus_hfi_register_iommu_domains(struct venus_hfi_device *device,
struct msm_vidc_platform_resources *res)
{
- struct msm_iova_partition partition[2];
- struct msm_iova_layout layout;
- int rc = 0;
- int i;
- struct msm_vidc_iommu_info *io_map;
+ struct iommu_domain *domain;
+ int rc = 0, i = 0;
+ struct iommu_set *iommu_group_set;
+ struct iommu_info *iommu_map;
- if (!device)
+ if (!device || !res)
return -EINVAL;
- io_map = device->resources.io_map;
+ iommu_group_set = &device->res->iommu_group_set;
- strlcpy(io_map[CP_MAP].name, "vidc-cp-map",
- sizeof(io_map[CP_MAP].name));
- strlcpy(io_map[CP_MAP].ctx, "venus_cp",
- sizeof(io_map[CP_MAP].ctx));
- strlcpy(io_map[NS_MAP].name, "vidc-ns-map",
- sizeof(io_map[NS_MAP].name));
- strlcpy(io_map[NS_MAP].ctx, "venus_ns",
- sizeof(io_map[NS_MAP].ctx));
-
- for (i = 0; i < MAX_MAP; i++) {
- if (!res->iommu_maps[i].addr_range[1])
- continue;
- memcpy(io_map[i].addr_range, &res->iommu_maps[i].addr_range,
- sizeof(u32) * 2);
-
- partition[0].start = io_map[i].addr_range[0];
- if (i == NS_MAP) {
- partition[0].size =
- io_map[i].addr_range[1] - SHARED_QSIZE;
- partition[1].start =
- partition[0].start + io_map[i].addr_range[1]
- - SHARED_QSIZE;
- partition[1].size = SHARED_QSIZE;
- layout.npartitions = 2;
- layout.is_secure = 0;
- } else {
- partition[0].size = io_map[i].addr_range[1];
- layout.npartitions = 1;
- layout.is_secure = 1;
+ for (i = 0; i < iommu_group_set->count; i++) {
+ iommu_map = &iommu_group_set->iommu_maps[i];
+ iommu_map->group = iommu_group_find(iommu_map->name);
+ if (!iommu_map->group) {
+ dprintk(VIDC_ERR, "Failed to find group :%s\n",
+ iommu_map->name);
+ goto fail_group;
}
- layout.partitions = &partition[0];
- layout.client_name = io_map[i].name;
- layout.domain_flags = 0;
- dprintk(VIDC_DBG, "Registering domain 1 with: %lx, %lx, %s\n",
- partition[0].start, partition[0].size,
- layout.client_name);
- dprintk(VIDC_DBG, "Registering domain 2 with: %lx, %lx, %s\n",
- partition[1].start, partition[1].size,
- layout.client_name);
- io_map[i].domain = msm_register_domain(&layout);
- if (io_map[i].domain < 0) {
- dprintk(VIDC_ERR, "Failed to register cp domain\n");
- rc = -EINVAL;
- break;
+ domain = iommu_group_get_iommudata(iommu_map->group);
+ if (!domain) {
+ dprintk(VIDC_ERR,
+ "Failed to get domain data for group %p",
+ iommu_map->group);
+ goto fail_group;
+ }
+ iommu_map->domain = msm_find_domain_no(domain);
+ if (iommu_map->domain < 0) {
+ dprintk(VIDC_ERR,
+ "Failed to get domain index for domain %p",
+ domain);
+ goto fail_group;
}
}
- /* There is no api provided as msm_unregister_domain, so
- * we are not able to unregister the previously
- * registered domains if any domain registration fails.*/
- BUG_ON(i < MAX_MAP);
return rc;
+
+fail_group:
+ for (--i; i >= 0; i--) {
+ iommu_map = &iommu_group_set->iommu_maps[i];
+ if (iommu_map->group)
+ iommu_group_put(iommu_map->group);
+ iommu_map->group = NULL;
+ iommu_map->domain = -1;
+ }
+ return -EINVAL;
+}
+
+static void venus_hfi_deregister_iommu_domains(struct venus_hfi_device *device)
+{
+ struct iommu_set *iommu_group_set;
+ struct iommu_info *iommu_map;
+ int i = 0;
+
+ if (!device)
+ return;
+
+ iommu_group_set = &device->res->iommu_group_set;
+ for (i = 0; i < iommu_group_set->count; i++) {
+ iommu_map = &iommu_group_set->iommu_maps[i];
+ if (iommu_map->group)
+ iommu_group_put(iommu_map->group);
+ iommu_map->group = NULL;
+ iommu_map->domain = -1;
+ }
}
static void venus_hfi_deinit_bus(struct venus_hfi_device *device)
@@ -2462,6 +2466,7 @@
static void venus_hfi_deinit_resources(struct venus_hfi_device *device)
{
venus_hfi_deinit_ocmem(device);
+ venus_hfi_deregister_iommu_domains(device);
venus_hfi_deinit_bus(device);
venus_hfi_deinit_clocks(device);
}
@@ -2471,39 +2476,39 @@
int rc;
struct iommu_domain *domain;
int i;
- struct msm_vidc_iommu_info *io_map;
- struct device *dev;
+ struct iommu_set *iommu_group_set;
+ struct iommu_group *group;
+ struct iommu_info *iommu_map;
- if (!device)
+ if (!device || !device->res)
return -EINVAL;
- for (i = 0; i < MAX_MAP; i++) {
- io_map = &device->resources.io_map[i];
- if (!io_map->domain)
- continue;
- dev = msm_iommu_get_ctx(io_map->ctx);
- domain = msm_get_iommu_domain(io_map->domain);
+ iommu_group_set = &device->res->iommu_group_set;
+ for (i = 0; i < iommu_group_set->count; i++) {
+ iommu_map = &iommu_group_set->iommu_maps[i];
+ group = iommu_map->group;
+ domain = msm_get_iommu_domain(iommu_map->domain);
if (IS_ERR_OR_NULL(domain)) {
dprintk(VIDC_ERR,
- "Failed to get domain: %s\n", io_map->name);
+ "Failed to get domain: %s\n", iommu_map->name);
rc = PTR_ERR(domain);
break;
}
- rc = iommu_attach_device(domain, dev);
+ rc = iommu_attach_group(domain, group);
if (rc) {
dprintk(VIDC_ERR,
- "IOMMU attach failed: %s\n", io_map->name);
+ "IOMMU attach failed: %s\n", iommu_map->name);
break;
}
}
- if (i < MAX_MAP) {
+ if (i < iommu_group_set->count) {
i--;
for (; i >= 0; i--) {
- io_map = &device->resources.io_map[i];
- dev = msm_iommu_get_ctx(io_map->ctx);
- domain = msm_get_iommu_domain(io_map->domain);
- if (dev && domain)
- iommu_detach_device(domain, dev);
+ iommu_map = &iommu_group_set->iommu_maps[i];
+ group = iommu_map->group;
+ domain = msm_get_iommu_domain(iommu_map->domain);
+ if (group && domain)
+ iommu_detach_group(domain, group);
}
}
return rc;
@@ -2511,51 +2516,40 @@
static void venus_hfi_iommu_detach(struct venus_hfi_device *device)
{
- struct device *dev;
+ struct iommu_group *group;
struct iommu_domain *domain;
- struct msm_vidc_iommu_info *io_map;
+ struct iommu_set *iommu_group_set;
+ struct iommu_info *iommu_map;
int i;
- if (!device) {
+ if (!device || !device->res) {
dprintk(VIDC_ERR, "Invalid paramter: %p\n", device);
return;
}
- for (i = 0; i < MAX_MAP; i++) {
- io_map = &device->resources.io_map[i];
- dev = msm_iommu_get_ctx(io_map->ctx);
- domain = msm_get_iommu_domain(io_map->domain);
- if (dev && domain)
- iommu_detach_device(domain, dev);
+ iommu_group_set = &device->res->iommu_group_set;
+ for (i = 0; i < iommu_group_set->count; i++) {
+ iommu_map = &iommu_group_set->iommu_maps[i];
+ group = iommu_map->group;
+ domain = msm_get_iommu_domain(iommu_map->domain);
+ if (group && domain)
+ iommu_detach_group(domain, group);
}
}
-static int venus_hfi_get_domain(void *dev, enum msm_vidc_io_maps iomap)
+static int venus_hfi_iommu_get_domain_partition(void *dev, u32 flags,
+ u32 buffer_type, int *domain, int *partition)
{
struct venus_hfi_device *device = dev;
- if (!device || iomap < CP_MAP || iomap >= MAX_MAP) {
- dprintk(VIDC_ERR, "%s: Invalid parameter: %p iomap: %d\n",
- __func__, device, iomap);
- return -EINVAL;
- }
- return device->resources.io_map[iomap].domain;
-}
-static int venus_hfi_iommu_get_map(void *dev,
- struct msm_vidc_iommu_info maps[MAX_MAP])
-{
- int i = 0;
- struct venus_hfi_device *device = dev;
-
- if (!device || !maps) {
- dprintk(VIDC_ERR, "%s: Invalid param device: %p maps: %p\n",
- __func__, device, maps);
+ if (!device) {
+ dprintk(VIDC_ERR, "%s: Invalid param device: %p\n",
+ __func__, device);
return -EINVAL;
}
- for (i = 0; i < MAX_MAP; i++)
- maps[i] = device->resources.io_map[i];
-
+ msm_smem_get_domain_partition(device->hal_client, flags, buffer_type,
+ domain, partition);
return 0;
}
@@ -2564,22 +2558,36 @@
struct tzbsp_memprot memprot;
unsigned int resp = 0;
int rc = 0;
- struct msm_vidc_iommu_info *io_map;
+ struct iommu_set *iommu_group_set;
+ struct iommu_info *iommu_map;
+ int i;
+
if (!device)
return -EINVAL;
- io_map = device->resources.io_map;
- if (!io_map) {
- dprintk(VIDC_ERR, "invalid params: %p\n", io_map);
+ iommu_group_set = &device->res->iommu_group_set;
+ if (!iommu_group_set) {
+ dprintk(VIDC_ERR, "invalid params: %p\n", iommu_group_set);
return -EINVAL;
}
- if (!io_map[CP_MAP].addr_range[1])
- return 0;
+
memprot.cp_start = 0x0;
- memprot.cp_size = io_map[CP_MAP].addr_range[0] +
- io_map[CP_MAP].addr_range[1];
- memprot.cp_nonpixel_start = 0;
- memprot.cp_nonpixel_size = 0;
+ memprot.cp_size = 0x0;
+ memprot.cp_nonpixel_start = 0x0;
+ memprot.cp_nonpixel_size = 0x0;
+
+ for (i = 0; i < iommu_group_set->count; i++) {
+ iommu_map = &iommu_group_set->iommu_maps[i];
+ if (strcmp(iommu_map->name, "venus_ns") == 0)
+ memprot.cp_size = iommu_map->addr_range[0].start;
+
+ if (strcmp(iommu_map->name, "venus_sec_non_pixel") == 0) {
+ memprot.cp_nonpixel_start =
+ iommu_map->addr_range[0].start;
+ memprot.cp_nonpixel_size =
+ iommu_map->addr_range[0].size;
+ }
+ }
rc = scm_call(SCM_SVC_CP, TZBSP_MEM_PROTECT_VIDEO_VAR, &memprot,
sizeof(memprot), &resp, sizeof(resp));
@@ -2833,8 +2841,7 @@
hdev->alloc_ocmem = venus_hfi_alloc_ocmem;
hdev->free_ocmem = venus_hfi_free_ocmem;
hdev->is_ocmem_present = venus_hfi_is_ocmem_present;
- hdev->get_domain = venus_hfi_get_domain;
- hdev->iommu_get_map = venus_hfi_iommu_get_map;
+ hdev->iommu_get_domain_partition = venus_hfi_iommu_get_domain_partition;
hdev->load_fw = venus_hfi_load_fw;
hdev->unload_fw = venus_hfi_unload_fw;
hdev->get_fw_info = venus_hfi_get_fw_info;
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.h b/drivers/media/platform/msm/vidc/venus_hfi.h
index 2ffb9d4..7a96ff4 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.h
+++ b/drivers/media/platform/msm/vidc/venus_hfi.h
@@ -164,7 +164,6 @@
struct venus_resources {
struct msm_vidc_fw fw;
- struct msm_vidc_iommu_info io_map[MAX_MAP];
struct venus_core_clock clock[VCODEC_MAX_CLKS];
struct venus_bus_info bus_info;
struct on_chip_mem ocmem;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index a057303..fad29f1 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -18,6 +18,7 @@
#include <linux/types.h>
#include <media/msm_vidc.h>
#include "msm_vidc_resources.h"
+#include "msm_smem.h"
#define CONTAINS(__a, __sz, __t) ({\
int __rc = __t >= __a && \
@@ -375,21 +376,6 @@
HAL_UNUSED_MVC_LEVEL = 0x10000000,
};
-enum hal_buffer {
- HAL_BUFFER_INPUT,
- HAL_BUFFER_OUTPUT,
- HAL_BUFFER_OUTPUT2,
- HAL_BUFFER_EXTRADATA_INPUT,
- HAL_BUFFER_EXTRADATA_OUTPUT,
- HAL_BUFFER_EXTRADATA_OUTPUT2,
- HAL_BUFFER_INTERNAL_SCRATCH,
- HAL_BUFFER_INTERNAL_SCRATCH_1,
- HAL_BUFFER_INTERNAL_SCRATCH_2,
- HAL_BUFFER_INTERNAL_PERSIST,
- HAL_BUFFER_INTERNAL_PERSIST_1,
- HAL_BUFFER_MAX
-};
-
struct hal_frame_rate {
enum hal_buffer buffer_type;
u32 frame_rate;
@@ -1061,9 +1047,8 @@
int (*alloc_ocmem)(void *dev, unsigned long size);
int (*free_ocmem)(void *dev);
int (*is_ocmem_present)(void *dev);
- int (*get_domain)(void *dev, enum msm_vidc_io_maps iomap);
- int (*iommu_get_map)(void *dev,
- struct msm_vidc_iommu_info maps[MAX_MAP]);
+ int (*iommu_get_domain_partition)(void *dev, u32 flags, u32 buffer_type,
+ int *domain_num, int *partition_num);
int (*load_fw)(void *dev);
void (*unload_fw)(void *dev);
int (*get_fw_info)(void *dev, enum fw_info info);
diff --git a/drivers/media/platform/msm/wfd/enc-venus-subdev.c b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
index b41ece6..40362f0 100644
--- a/drivers/media/platform/msm/wfd/enc-venus-subdev.c
+++ b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
@@ -46,7 +46,6 @@
bool callback_thread_running;
struct completion dq_complete, cmd_complete;
bool secure;
- int domain;
};
int venc_load_fw(struct v4l2_subdev *sd)
@@ -252,18 +251,6 @@
return msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
}
-static long get_iommu_domain(struct venc_inst *inst)
-{
- struct msm_vidc_iommu_info maps[MAX_MAP];
- int rc = msm_vidc_get_iommu_maps(inst->vidc_context, maps);
- if (rc) {
- WFD_MSG_ERR("Failed to retreive domain mappings\n");
- return rc;
- }
-
- return maps[inst->secure ? CP_MAP : NS_MAP].domain;
-}
-
static long venc_open(struct v4l2_subdev *sd, void *arg)
{
struct venc_inst *inst = NULL;
@@ -316,12 +303,6 @@
goto vidc_subscribe_fail;
}
- inst->domain = get_iommu_domain(inst);
- if (inst->domain < 0) {
- WFD_MSG_ERR("Failed to get domain\n");
- goto vidc_subscribe_fail;
- }
-
inst->callback_thread = kthread_run(venc_vidc_callback_thread, inst,
"venc_vidc_callback_thread");
if (IS_ERR(inst->callback_thread)) {
@@ -641,7 +622,9 @@
struct mem_region *mregion)
{
int rc = 0;
- unsigned long size = 0, align_req = 0;
+ unsigned long size = 0, align_req = 0, flags = 0;
+ int domain = 0, partition = 0;
+
if (!mregion) {
rc = -EINVAL;
goto venc_map_fail;
@@ -663,6 +646,12 @@
goto venc_map_fail;
}
+ rc = ion_handle_get_flags(venc_ion_client, mregion->ion_handle, &flags);
+ if (rc) {
+ WFD_MSG_ERR("Failed to get ion flags %d\n", rc);
+ goto venc_map_fail;
+ }
+
if (!inst->secure) {
mregion->kvaddr = ion_map_kernel(venc_ion_client,
mregion->ion_handle);
@@ -685,10 +674,16 @@
}
}
- rc = ion_map_iommu(venc_ion_client, mregion->ion_handle,
- inst->domain, 0, align_req, 0,
- (unsigned long *)&mregion->paddr, &size, 0, 0);
+ rc = msm_vidc_get_iommu_domain_partition(inst->vidc_context,
+ flags, BUF_TYPE_OUTPUT, &domain, &partition);
+ if (rc) {
+ WFD_MSG_ERR("Failed to get domain for output buffer\n");
+ goto venc_domain_fail;
+ }
+ rc = ion_map_iommu(venc_ion_client, mregion->ion_handle,
+ domain, partition, align_req, 0,
+ (unsigned long *)&mregion->paddr, &size, 0, 0);
if (rc) {
WFD_MSG_ERR("Failed to map into iommu\n");
goto venc_map_iommu_map_fail;
@@ -700,8 +695,8 @@
return 0;
venc_map_iommu_size_fail:
ion_unmap_iommu(venc_ion_client, mregion->ion_handle,
- inst->domain, 0);
-
+ domain, partition);
+venc_domain_fail:
if (inst->secure)
msm_ion_unsecure_buffer(venc_ion_client, mregion->ion_handle);
venc_map_iommu_map_fail:
@@ -714,12 +709,28 @@
static int venc_unmap_user_to_kernel(struct venc_inst *inst,
struct mem_region *mregion)
{
+ unsigned long flags = 0;
+ int domain = 0, partition = 0, rc = 0;
+
if (!mregion || !mregion->ion_handle)
return 0;
+ rc = ion_handle_get_flags(venc_ion_client, mregion->ion_handle, &flags);
+ if (rc) {
+ WFD_MSG_ERR("Failed to get ion flags %d\n", rc);
+ return rc;
+ }
+
+ rc = msm_vidc_get_iommu_domain_partition(inst->vidc_context,
+ flags, BUF_TYPE_OUTPUT, &domain, &partition);
+ if (rc) {
+ WFD_MSG_ERR("Failed to get domain for input buffer\n");
+ return rc;
+ }
+
if (mregion->paddr) {
ion_unmap_iommu(venc_ion_client, mregion->ion_handle,
- inst->domain, 0);
+ domain, partition);
mregion->paddr = NULL;
}
@@ -731,7 +742,7 @@
if (inst->secure)
msm_ion_unsecure_buffer(venc_ion_client, mregion->ion_handle);
- return 0;
+ return rc;
}
static long venc_set_output_buffer(struct v4l2_subdev *sd, void *arg)
@@ -1145,7 +1156,8 @@
{
struct mem_region_map *mmap = arg;
struct mem_region *mregion = NULL;
- unsigned long rc = 0, size = 0, align_req = 0;
+ unsigned long size = 0, align_req = 0, flags = 0;
+ int domain = 0, partition = 0, rc = 0;
void *paddr = NULL;
struct venc_inst *inst = NULL;
@@ -1167,21 +1179,34 @@
goto venc_map_bad_align;
}
+ rc = ion_handle_get_flags(mmap->ion_client, mregion->ion_handle,
+ &flags);
+ if (rc) {
+ WFD_MSG_ERR("Failed to get ion flags %d\n", rc);
+ goto venc_map_bad_align;
+ }
+
if (inst->secure) {
rc = msm_ion_secure_buffer(mmap->ion_client,
- mregion->ion_handle, VIDEO_PIXEL, 0);
+ mregion->ion_handle, VIDEO_PIXEL, 0);
if (rc) {
WFD_MSG_ERR("Failed to secure input buffer\n");
goto venc_map_bad_align;
}
}
- rc = ion_map_iommu(mmap->ion_client, mregion->ion_handle,
- inst->domain, 0, align_req, 0, (unsigned long *)&paddr,
- &size, 0, 0);
-
+ rc = msm_vidc_get_iommu_domain_partition(inst->vidc_context,
+ flags, BUF_TYPE_INPUT, &domain, &partition);
if (rc) {
- WFD_MSG_ERR("Failed to get physical addr %ld\n", rc);
+ WFD_MSG_ERR("Failed to get domain for output buffer\n");
+ goto venc_map_domain_fail;
+ }
+
+ rc = ion_map_iommu(mmap->ion_client, mregion->ion_handle,
+ domain, partition, align_req, 0,
+ (unsigned long *)&paddr, &size, 0, 0);
+ if (rc) {
+ WFD_MSG_ERR("Failed to get physical addr %d\n", rc);
paddr = NULL;
goto venc_map_bad_align;
} else if (size < mregion->size) {
@@ -1191,12 +1216,12 @@
}
mregion->paddr = paddr;
- return 0;
+ return rc;
venc_map_iommu_size_fail:
ion_unmap_iommu(venc_ion_client, mregion->ion_handle,
- inst->domain, 0);
-
+ domain, partition);
+venc_map_domain_fail:
if (inst->secure)
msm_ion_unsecure_buffer(mmap->ion_client, mregion->ion_handle);
venc_map_bad_align:
@@ -1208,6 +1233,8 @@
struct mem_region_map *mmap = arg;
struct mem_region *mregion = NULL;
struct venc_inst *inst = NULL;
+ unsigned long flags = 0;
+ int domain = 0, partition = 0, rc = 0;
if (!sd) {
WFD_MSG_ERR("Subdevice required for %s\n", __func__);
@@ -1220,14 +1247,28 @@
inst = (struct venc_inst *)sd->dev_priv;
mregion = mmap->mregion;
+ rc = ion_handle_get_flags(mmap->ion_client,
+ mregion->ion_handle, &flags);
+ if (rc) {
+ WFD_MSG_ERR("Failed to get ion flags %d\n", rc);
+ return rc;
+ }
+
+ rc = msm_vidc_get_iommu_domain_partition(inst->vidc_context,
+ flags, BUF_TYPE_INPUT, &domain, &partition);
+ if (rc) {
+ WFD_MSG_ERR("Failed to get domain for input buffer\n");
+ return rc;
+ }
+
if (mregion->paddr)
ion_unmap_iommu(mmap->ion_client, mregion->ion_handle,
- inst->domain, 0);
+ domain, partition);
if (inst->secure)
msm_ion_unsecure_buffer(mmap->ion_client, mregion->ion_handle);
- return 0;
+ return rc;
}
static long venc_set_framerate_mode(struct v4l2_subdev *sd,
@@ -1239,24 +1280,6 @@
return 0;
}
-static long secure_toggle(struct venc_inst *inst, bool secure)
-{
- if (inst->secure == secure)
- return 0;
-
- if (!list_empty(&inst->registered_input_bufs.list) ||
- !list_empty(&inst->registered_output_bufs.list)) {
- WFD_MSG_ERR(
- "Attempt to (un)secure encoder not allowed after registering buffers"
- );
- return -EEXIST;
- }
-
- inst->secure = secure;
- inst->domain = get_iommu_domain(inst);
- return 0;
-}
-
static long venc_secure(struct v4l2_subdev *sd)
{
struct venc_inst *inst = NULL;
@@ -1269,9 +1292,18 @@
}
inst = sd->dev_priv;
- rc = secure_toggle(inst, true);
- if (rc) {
- WFD_MSG_ERR("Failed to toggle into secure mode\n");
+
+ if (!list_empty(&inst->registered_input_bufs.list) ||
+ !list_empty(&inst->registered_output_bufs.list)) {
+ WFD_MSG_ERR(
+ "Attempt to (un)secure encoder not allowed after registering buffers"
+ );
+ rc = -EEXIST;
+ }
+
+ if (inst->secure) {
+ /* Nothing to do! */
+ rc = 0;
goto secure_fail;
}
@@ -1282,9 +1314,8 @@
goto secure_fail;
}
- return 0;
+ inst->secure = true;
secure_fail:
- secure_toggle(sd->dev_priv, false);
return rc;
}
diff --git a/drivers/media/platform/msm/wfd/vsg-subdev.c b/drivers/media/platform/msm/wfd/vsg-subdev.c
index bbe2b7b..90b1957 100644
--- a/drivers/media/platform/msm/wfd/vsg-subdev.c
+++ b/drivers/media/platform/msm/wfd/vsg-subdev.c
@@ -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
@@ -101,8 +101,8 @@
list_for_each_entry(temp, &context->busy_queue.node, node) {
if (++count > MAX_BUFS_BUSY_WITH_ENC) {
- WFD_MSG_WARN("Skipping encode, too many "
- "buffers with encoder");
+ WFD_MSG_WARN(
+ "Skipping encode, too many buffers with encoder\n");
goto err_skip_encode;
}
}
@@ -158,8 +158,11 @@
&& can_release) {
vsg_release_input_buffer(context,
old_last_buffer);
- kfree(old_last_buffer);
}
+
+ if (last_buf_with_us)
+ kfree(old_last_buffer);
+
}
vsg_set_last_buffer(context, buf_info);
}
@@ -406,8 +409,8 @@
if (!is_last_buffer &&
!(temp->flags & VSG_NEVER_RELEASE)) {
vsg_release_input_buffer(context, temp);
- kfree(temp);
}
+ kfree(temp);
}
}
@@ -458,8 +461,8 @@
static long vsg_return_ip_buffer(struct v4l2_subdev *sd, void *arg)
{
struct vsg_context *context = NULL;
- struct vsg_buf_info *buf_info, *last_buffer,
- *expected_buffer;
+ struct vsg_buf_info *buf_info = NULL, *last_buffer = NULL,
+ *expected_buffer = NULL;
int rc = 0;
if (!arg || !sd) {
@@ -473,8 +476,10 @@
buf_info = (struct vsg_buf_info *)arg;
last_buffer = context->last_buffer;
- expected_buffer = list_first_entry(&context->busy_queue.node,
- struct vsg_buf_info, node);
+ if (!list_empty(&context->busy_queue.node)) {
+ expected_buffer = list_first_entry(&context->busy_queue.node,
+ struct vsg_buf_info, node);
+ }
WFD_MSG_DBG("Return frame with paddr %p\n",
(void *)buf_info->mdp_buf_info.paddr);
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 11a8f4d..1f3dc2f 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -49,6 +49,7 @@
static char utf_8_flag;
static char rt_ert_flag;
static char formatting_dir;
+static DEFINE_MUTEX(iris_fm);
module_param(rds_buf, uint, 0);
MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
@@ -1167,6 +1168,7 @@
DECLARE_WAITQUEUE(wait, current);
+ mutex_lock(&iris_fm);
hdev->req_status = HCI_REQ_PEND;
add_wait_queue(&hdev->req_wait_q, &wait);
@@ -1178,8 +1180,10 @@
remove_wait_queue(&hdev->req_wait_q, &wait);
- if (signal_pending(current))
+ if (signal_pending(current)) {
+ mutex_unlock(&iris_fm);
return -EINTR;
+ }
switch (hdev->req_status) {
case HCI_REQ_DONE:
@@ -1197,6 +1201,7 @@
}
hdev->req_status = hdev->req_result = 0;
+ mutex_unlock(&iris_fm);
return err;
}
@@ -3744,6 +3749,31 @@
return retval;
}
+static int iris_fops_release(struct file *file)
+{
+ struct iris_device *radio = video_get_drvdata(video_devdata(file));
+ int retval = 0;
+
+ FMDBG("Enter %s ", __func__);
+ if (radio == NULL)
+ return -EINVAL;
+
+ if (radio->mode == FM_OFF)
+ return 0;
+
+ if (radio->mode == FM_RECV)
+ retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
+ radio->fm_hdev);
+ else if (radio->mode == FM_TRANS)
+ retval = hci_cmd(HCI_FM_DISABLE_TRANS_CMD,
+ radio->fm_hdev);
+ if (retval < 0)
+ FMDERR("Err on disable FM %d\n", retval);
+
+ radio->mode = FM_OFF;
+ return retval;
+}
+
static int iris_vidioc_dqbuf(struct file *file, void *priv,
struct v4l2_buffer *buffer)
{
@@ -3838,6 +3868,7 @@
static const struct v4l2_file_operations iris_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = video_ioctl2,
+ .release = iris_fops_release,
};
static struct video_device iris_viddev_template = {
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index a79009b..d3ddeef 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -1354,13 +1354,16 @@
/* Set channel spacing */
switch (region) {
case TAVARUA_REGION_US:
- if (adie_type_bahma) {
+ if ((adie_type_bahma) && (bahama_version == 0x09)) {
FMDBG("Adie type : Bahama\n");
/*
Configuring all 200KHZ spaced regions as 100KHz due to
change in the new Bahma FM SoC search algorithm.
*/
value = FM_CH_SPACE_100KHZ;
+ } else if ((adie_type_bahma) && (bahama_version == 0x0a)) {
+ FMDBG("Adie type : Bahama B1\n");
+ value = FM_CH_SPACE_200KHZ;
} else {
FMDBG("Adie type : Marimba\n");
value = FM_CH_SPACE_200KHZ;
@@ -1368,7 +1371,7 @@
break;
case TAVARUA_REGION_JAPAN:
case TAVARUA_REGION_OTHER:
- if (adie_type_bahma) {
+ if ((adie_type_bahma) && (bahama_version == 0x09)) {
FMDBG("Adie type : Bahama\n");
FMDBG("%s: Configuring the channel-spacing as 50KHz"
"for the Region : %d", __func__, region);
@@ -1377,6 +1380,9 @@
change in the new Bahma FM SoC search algorithm.
*/
value = FM_CH_SPACE_50KHZ;
+ } else if ((adie_type_bahma) && (bahama_version == 0x0a)) {
+ FMDBG("Adie type : Bahama B1\n");
+ value = FM_CH_SPACE_100KHZ;
} else {
FMDBG("Adie type : Marimba\n");
value = FM_CH_SPACE_100KHZ;
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index a037c17..cf6f97c 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -3016,14 +3016,27 @@
{
struct mmc_blk_data *part_md;
struct mmc_blk_data *md = mmc_get_drvdata(card);
+ int rc = 0;
if (md) {
- mmc_queue_suspend(&md->queue);
+ rc = mmc_queue_suspend(&md->queue);
+ if (rc)
+ goto out;
list_for_each_entry(part_md, &md->part, part) {
- mmc_queue_suspend(&part_md->queue);
+ rc = mmc_queue_suspend(&part_md->queue);
+ if (rc)
+ goto out_resume;
}
}
- return 0;
+ goto out;
+
+ out_resume:
+ mmc_queue_resume(&md->queue);
+ list_for_each_entry(part_md, &md->part, part) {
+ mmc_queue_resume(&part_md->queue);
+ }
+ out:
+ return rc;
}
static int mmc_blk_resume(struct mmc_card *card)
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 64ece67..65a1322 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -435,10 +435,11 @@
* complete any outstanding requests. This ensures that we
* won't suspend while a request is being processed.
*/
-void mmc_queue_suspend(struct mmc_queue *mq)
+int mmc_queue_suspend(struct mmc_queue *mq)
{
struct request_queue *q = mq->queue;
unsigned long flags;
+ int rc = 0;
if (!(mq->flags & MMC_QUEUE_SUSPENDED)) {
mq->flags |= MMC_QUEUE_SUSPENDED;
@@ -447,8 +448,20 @@
blk_stop_queue(q);
spin_unlock_irqrestore(q->queue_lock, flags);
- down(&mq->thread_sem);
+ rc = down_trylock(&mq->thread_sem);
+ if (rc) {
+ /*
+ * Failed to take the lock so better to abort the
+ * suspend because mmcqd thread is processing requests.
+ */
+ mq->flags &= ~MMC_QUEUE_SUSPENDED;
+ spin_lock_irqsave(q->queue_lock, flags);
+ blk_start_queue(q);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+ rc = -EBUSY;
+ }
}
+ return rc;
}
/**
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index 99c3c60..9280d1b 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -60,7 +60,7 @@
extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
const char *);
extern void mmc_cleanup_queue(struct mmc_queue *);
-extern void mmc_queue_suspend(struct mmc_queue *);
+extern int mmc_queue_suspend(struct mmc_queue *);
extern void mmc_queue_resume(struct mmc_queue *);
extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index be4315e..b395fc8 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1907,6 +1907,14 @@
mmc_host_clk_release(host);
}
+void mmc_power_cycle(struct mmc_host *host)
+{
+ mmc_power_off(host);
+ /* Wait at least 1 ms according to SD spec */
+ mmc_delay(1);
+ mmc_power_up(host);
+}
+
/*
* Cleanup when the last reference to the bus operator is dropped.
*/
@@ -2571,7 +2579,7 @@
if (!host->bus_ops->power_restore)
return -EOPNOTSUPP;
- if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
+ if (!(host->caps & MMC_CAP_HW_RESET))
return -EOPNOTSUPP;
if (!card)
@@ -2583,7 +2591,10 @@
mmc_host_clk_hold(host);
mmc_set_clock(host, host->f_init);
- host->ops->hw_reset(host);
+ if (mmc_card_sd(card))
+ mmc_power_cycle(host);
+ else if (host->ops->hw_reset)
+ host->ops->hw_reset(host);
/* If the reset has happened, then a status command will fail */
if (check) {
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 6fa51e0..153c821 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -48,6 +48,7 @@
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
void mmc_power_off(struct mmc_host *host);
+void mmc_power_cycle(struct mmc_host *host);
static inline void mmc_delay(unsigned int ms)
{
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 14038ed..07850b9 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -27,9 +27,16 @@
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/wait.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/mmc/mmc.h>
+#include <mach/gpio.h>
#include "sdhci-pltfm.h"
+#define SDHCI_VER_100 0x2B
#define CORE_HC_MODE 0x78
#define HC_MODE_EN 0x1
@@ -52,6 +59,43 @@
#define CORE_PWRCTL_IO_FAIL (1 << 3)
#define INT_MASK 0xF
+#define MAX_PHASES 16
+
+#define CORE_DLL_LOCK (1 << 7)
+#define CORE_DLL_EN (1 << 16)
+#define CORE_CDR_EN (1 << 17)
+#define CORE_CK_OUT_EN (1 << 18)
+#define CORE_CDR_EXT_EN (1 << 19)
+#define CORE_DLL_PDN (1 << 29)
+#define CORE_DLL_RST (1 << 30)
+#define CORE_DLL_CONFIG 0x100
+#define CORE_DLL_TEST_CTL 0x104
+#define CORE_DLL_STATUS 0x108
+
+#define CORE_VENDOR_SPEC 0x10C
+#define CORE_CLK_PWRSAVE (1 << 1)
+#define CORE_IO_PAD_PWR_SWITCH (1 << 16)
+
+/* 8KB descriptors */
+#define SDHCI_MSM_MAX_SEGMENTS (1 << 13)
+
+static const u32 tuning_block_64[] = {
+ 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
+ 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
+ 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
+ 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
+};
+
+static const u32 tuning_block_128[] = {
+ 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
+ 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
+ 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
+ 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
+ 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
+ 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
+ 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
+ 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
+};
/* This structure keeps information per regulator */
struct sdhci_msm_reg_data {
@@ -96,13 +140,43 @@
u8 size;
};
+struct sdhci_msm_pad_pull {
+ enum msm_tlmm_pull_tgt no;
+ u32 val;
+};
+
+struct sdhci_msm_pad_pull_data {
+ struct sdhci_msm_pad_pull *on;
+ struct sdhci_msm_pad_pull *off;
+ u8 size;
+};
+
+struct sdhci_msm_pad_drv {
+ enum msm_tlmm_hdrive_tgt no;
+ u32 val;
+};
+
+struct sdhci_msm_pad_drv_data {
+ struct sdhci_msm_pad_drv *on;
+ struct sdhci_msm_pad_drv *off;
+ u8 size;
+};
+
+struct sdhci_msm_pad_data {
+ struct sdhci_msm_pad_pull_data *pull;
+ struct sdhci_msm_pad_drv_data *drv;
+};
+
+
struct sdhci_msm_pin_data {
/*
* = 1 if controller pins are using gpios
* = 0 if controller has dedicated MSM pads
*/
+ u8 is_gpio;
bool cfg_sts;
struct sdhci_msm_gpio_data *gpio_data;
+ struct sdhci_msm_pad_data *pad_data;
};
struct sdhci_msm_pltfm_data {
@@ -142,6 +216,403 @@
VDD_IO_SET_LEVEL,
};
+/* MSM platform specific tuning */
+static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host,
+ u8 poll)
+{
+ int rc = 0;
+ u32 wait_cnt = 50;
+ u8 ck_out_en = 0;
+ struct mmc_host *mmc = host->mmc;
+
+ /* poll for CK_OUT_EN bit. max. poll time = 50us */
+ ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) &
+ CORE_CK_OUT_EN);
+
+ while (ck_out_en != poll) {
+ if (--wait_cnt == 0) {
+ pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
+ mmc_hostname(mmc), __func__, poll);
+ rc = -ETIMEDOUT;
+ goto out;
+ }
+ udelay(1);
+
+ ck_out_en = !!(readl_relaxed(host->ioaddr +
+ CORE_DLL_CONFIG) & CORE_CK_OUT_EN);
+ }
+out:
+ return rc;
+}
+
+static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)
+{
+ int rc = 0;
+ u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
+ 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
+ 0x8};
+ unsigned long flags;
+ u32 config;
+ struct mmc_host *mmc = host->mmc;
+
+ pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
+ spin_lock_irqsave(&host->lock, flags);
+
+ config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
+ config &= ~(CORE_CDR_EN | CORE_CK_OUT_EN);
+ config |= (CORE_CDR_EXT_EN | CORE_DLL_EN);
+ writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+
+ /* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '0' */
+ rc = msm_dll_poll_ck_out_en(host, 0);
+ if (rc)
+ goto err_out;
+
+ /*
+ * Write the selected DLL clock output phase (0 ... 15)
+ * to CDR_SELEXT bit field of DLL_CONFIG register.
+ */
+ writel_relaxed(((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+ & ~(0xF << 20))
+ | (grey_coded_phase_table[phase] << 20)),
+ host->ioaddr + CORE_DLL_CONFIG);
+
+ /* Set CK_OUT_EN bit of DLL_CONFIG register to 1. */
+ writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+ | CORE_CK_OUT_EN), host->ioaddr + CORE_DLL_CONFIG);
+
+ /* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '1' */
+ rc = msm_dll_poll_ck_out_en(host, 1);
+ if (rc)
+ goto err_out;
+
+ config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
+ config |= CORE_CDR_EN;
+ config &= ~CORE_CDR_EXT_EN;
+ writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+ goto out;
+
+err_out:
+ pr_err("%s: %s: Failed to set DLL phase: %d\n",
+ mmc_hostname(mmc), __func__, phase);
+out:
+ spin_unlock_irqrestore(&host->lock, flags);
+ pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
+ return rc;
+}
+
+/*
+ * Find out the greatest range of consecuitive selected
+ * DLL clock output phases that can be used as sampling
+ * setting for SD3.0 UHS-I card read operation (in SDR104
+ * timing mode) or for eMMC4.5 card read operation (in HS200
+ * timing mode).
+ * Select the 3/4 of the range and configure the DLL with the
+ * selected DLL clock output phase.
+ */
+
+static int msm_find_most_appropriate_phase(struct sdhci_host *host,
+ u8 *phase_table, u8 total_phases)
+{
+ int ret;
+ u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
+ u8 phases_per_row[MAX_PHASES] = {0};
+ int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
+ int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
+ bool phase_0_found = false, phase_15_found = false;
+ struct mmc_host *mmc = host->mmc;
+
+ pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
+ if (!total_phases || (total_phases > MAX_PHASES)) {
+ pr_err("%s: %s: invalid argument: total_phases=%d\n",
+ mmc_hostname(mmc), __func__, total_phases);
+ return -EINVAL;
+ }
+
+ for (cnt = 0; cnt < total_phases; cnt++) {
+ ranges[row_index][col_index] = phase_table[cnt];
+ phases_per_row[row_index] += 1;
+ col_index++;
+
+ if ((cnt + 1) == total_phases) {
+ continue;
+ /* check if next phase in phase_table is consecutive or not */
+ } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
+ row_index++;
+ col_index = 0;
+ }
+ }
+
+ if (row_index >= MAX_PHASES)
+ return -EINVAL;
+
+ /* Check if phase-0 is present in first valid window? */
+ if (!ranges[0][0]) {
+ phase_0_found = true;
+ phase_0_raw_index = 0;
+ /* Check if cycle exist between 2 valid windows */
+ for (cnt = 1; cnt <= row_index; cnt++) {
+ if (phases_per_row[cnt]) {
+ for (i = 0; i < phases_per_row[cnt]; i++) {
+ if (ranges[cnt][i] == 15) {
+ phase_15_found = true;
+ phase_15_raw_index = cnt;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* If 2 valid windows form cycle then merge them as single window */
+ if (phase_0_found && phase_15_found) {
+ /* number of phases in raw where phase 0 is present */
+ u8 phases_0 = phases_per_row[phase_0_raw_index];
+ /* number of phases in raw where phase 15 is present */
+ u8 phases_15 = phases_per_row[phase_15_raw_index];
+
+ if (phases_0 + phases_15 >= MAX_PHASES)
+ /*
+ * If there are more than 1 phase windows then total
+ * number of phases in both the windows should not be
+ * more than or equal to MAX_PHASES.
+ */
+ return -EINVAL;
+
+ /* Merge 2 cyclic windows */
+ i = phases_15;
+ for (cnt = 0; cnt < phases_0; cnt++) {
+ ranges[phase_15_raw_index][i] =
+ ranges[phase_0_raw_index][cnt];
+ if (++i >= MAX_PHASES)
+ break;
+ }
+
+ phases_per_row[phase_0_raw_index] = 0;
+ phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
+ }
+
+ for (cnt = 0; cnt <= row_index; cnt++) {
+ if (phases_per_row[cnt] > curr_max) {
+ curr_max = phases_per_row[cnt];
+ selected_row_index = cnt;
+ }
+ }
+
+ i = ((curr_max * 3) / 4);
+ if (i)
+ i--;
+
+ ret = (int)ranges[selected_row_index][i];
+
+ if (ret >= MAX_PHASES) {
+ ret = -EINVAL;
+ pr_err("%s: %s: invalid phase selected=%d\n",
+ mmc_hostname(mmc), __func__, ret);
+ }
+
+ pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
+ return ret;
+}
+
+static inline void msm_cm_dll_set_freq(struct sdhci_host *host)
+{
+ u32 mclk_freq = 0;
+
+ /* Program the MCLK value to MCLK_FREQ bit field */
+ if (host->clock <= 112000000)
+ mclk_freq = 0;
+ else if (host->clock <= 125000000)
+ mclk_freq = 1;
+ else if (host->clock <= 137000000)
+ mclk_freq = 2;
+ else if (host->clock <= 150000000)
+ mclk_freq = 3;
+ else if (host->clock <= 162000000)
+ mclk_freq = 4;
+ else if (host->clock <= 175000000)
+ mclk_freq = 5;
+ else if (host->clock <= 187000000)
+ mclk_freq = 6;
+ else if (host->clock <= 200000000)
+ mclk_freq = 7;
+
+ writel_relaxed(((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+ & ~(7 << 24)) | (mclk_freq << 24)),
+ host->ioaddr + CORE_DLL_CONFIG);
+}
+
+/* Initialize the DLL (Programmable Delay Line ) */
+static int msm_init_cm_dll(struct sdhci_host *host)
+{
+ struct mmc_host *mmc = host->mmc;
+ int rc = 0;
+ unsigned long flags;
+ u32 wait_cnt;
+
+ pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
+ spin_lock_irqsave(&host->lock, flags);
+
+ /*
+ * Make sure that clock is always enabled when DLL
+ * tuning is in progress. Keeping PWRSAVE ON may
+ * turn off the clock. So let's disable the PWRSAVE
+ * here and re-enable it once tuning is completed.
+ */
+ writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
+ & ~CORE_CLK_PWRSAVE),
+ host->ioaddr + CORE_VENDOR_SPEC);
+
+ /* Write 1 to DLL_RST bit of DLL_CONFIG register */
+ writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+ | CORE_DLL_RST), host->ioaddr + CORE_DLL_CONFIG);
+
+ /* Write 1 to DLL_PDN bit of DLL_CONFIG register */
+ writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+ | CORE_DLL_PDN), host->ioaddr + CORE_DLL_CONFIG);
+ msm_cm_dll_set_freq(host);
+
+ /* Write 0 to DLL_RST bit of DLL_CONFIG register */
+ writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+ & ~CORE_DLL_RST), host->ioaddr + CORE_DLL_CONFIG);
+
+ /* Write 0 to DLL_PDN bit of DLL_CONFIG register */
+ writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+ & ~CORE_DLL_PDN), host->ioaddr + CORE_DLL_CONFIG);
+
+ /* Set DLL_EN bit to 1. */
+ writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+ | CORE_DLL_EN), host->ioaddr + CORE_DLL_CONFIG);
+
+ /* Set CK_OUT_EN bit to 1. */
+ writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+ | CORE_CK_OUT_EN), host->ioaddr + CORE_DLL_CONFIG);
+
+ wait_cnt = 50;
+ /* Wait until DLL_LOCK bit of DLL_STATUS register becomes '1' */
+ while (!(readl_relaxed(host->ioaddr + CORE_DLL_STATUS) &
+ CORE_DLL_LOCK)) {
+ /* max. wait for 50us sec for LOCK bit to be set */
+ if (--wait_cnt == 0) {
+ pr_err("%s: %s: DLL failed to LOCK\n",
+ mmc_hostname(mmc), __func__);
+ rc = -ETIMEDOUT;
+ goto out;
+ }
+ /* wait for 1us before polling again */
+ udelay(1);
+ }
+
+out:
+ /* re-enable PWRSAVE */
+ writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) |
+ CORE_CLK_PWRSAVE),
+ host->ioaddr + CORE_VENDOR_SPEC);
+ spin_unlock_irqrestore(&host->lock, flags);
+ pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
+ return rc;
+}
+
+int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
+{
+ unsigned long flags;
+ u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
+ const u32 *tuning_block_pattern = tuning_block_64;
+ int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
+ int rc;
+ struct mmc_host *mmc = host->mmc;
+
+ pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
+ /* Tuning is only required for SDR104 modes */
+ spin_lock_irqsave(&host->lock, flags);
+
+ if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
+ (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
+ tuning_block_pattern = tuning_block_128;
+ size = sizeof(tuning_block_128);
+ }
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ /* first of all reset the tuning block */
+ rc = msm_init_cm_dll(host);
+ if (rc)
+ goto out;
+
+ data_buf = kmalloc(size, GFP_KERNEL);
+ if (!data_buf) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ phase = 0;
+ do {
+ struct mmc_command cmd = {0};
+ struct mmc_data data = {0};
+ struct mmc_request mrq = {
+ .cmd = &cmd,
+ .data = &data
+ };
+ struct scatterlist sg;
+
+ /* set the phase in delay line hw block */
+ rc = msm_config_cm_dll_phase(host, phase);
+ if (rc)
+ goto kfree;
+
+ cmd.opcode = opcode;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ data.blksz = size;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+ data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
+
+ data.sg = &sg;
+ data.sg_len = 1;
+ sg_init_one(&sg, data_buf, size);
+ memset(data_buf, 0, size);
+ mmc_wait_for_req(mmc, &mrq);
+
+ if (!cmd.error && !data.error &&
+ !memcmp(data_buf, tuning_block_pattern, size)) {
+ /* tuning is successful at this tuning point */
+ tuned_phases[tuned_phase_cnt++] = phase;
+ pr_debug("%s: %s: found good phase = %d\n",
+ mmc_hostname(mmc), __func__, phase);
+ }
+ } while (++phase < 16);
+
+ if (tuned_phase_cnt) {
+ rc = msm_find_most_appropriate_phase(host, tuned_phases,
+ tuned_phase_cnt);
+ if (rc < 0)
+ goto kfree;
+ else
+ phase = (u8)rc;
+
+ /*
+ * Finally set the selected phase in delay
+ * line hw block.
+ */
+ rc = msm_config_cm_dll_phase(host, phase);
+ if (rc)
+ goto kfree;
+ pr_debug("%s: %s: finally setting the tuning phase to %d\n",
+ mmc_hostname(mmc), __func__, phase);
+ } else {
+ /* tuning failed */
+ pr_err("%s: %s: no tuning point found\n",
+ mmc_hostname(mmc), __func__);
+ rc = -EAGAIN;
+ }
+
+kfree:
+ kfree(data_buf);
+out:
+ pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
+ return rc;
+}
+
static int sdhci_msm_setup_gpio(struct sdhci_msm_pltfm_data *pdata, bool enable)
{
struct sdhci_msm_gpio_data *curr;
@@ -180,20 +651,88 @@
return ret;
}
+static int sdhci_msm_setup_pad(struct sdhci_msm_pltfm_data *pdata, bool enable)
+{
+ struct sdhci_msm_pad_data *curr;
+ int i;
+
+ curr = pdata->pin_data->pad_data;
+ for (i = 0; i < curr->drv->size; i++) {
+ if (enable)
+ msm_tlmm_set_hdrive(curr->drv->on[i].no,
+ curr->drv->on[i].val);
+ else
+ msm_tlmm_set_hdrive(curr->drv->off[i].no,
+ curr->drv->off[i].val);
+ }
+
+ for (i = 0; i < curr->pull->size; i++) {
+ if (enable)
+ msm_tlmm_set_pull(curr->pull->on[i].no,
+ curr->pull->on[i].val);
+ else
+ msm_tlmm_set_pull(curr->pull->off[i].no,
+ curr->pull->off[i].val);
+ }
+
+ return 0;
+}
+
static int sdhci_msm_setup_pins(struct sdhci_msm_pltfm_data *pdata, bool enable)
{
int ret = 0;
if (!pdata->pin_data || (pdata->pin_data->cfg_sts == enable))
return 0;
+ if (pdata->pin_data->is_gpio)
+ ret = sdhci_msm_setup_gpio(pdata, enable);
+ else
+ ret = sdhci_msm_setup_pad(pdata, enable);
- ret = sdhci_msm_setup_gpio(pdata, enable);
if (!ret)
pdata->pin_data->cfg_sts = enable;
return ret;
}
+static int sdhci_msm_dt_get_array(struct device *dev, const char *prop_name,
+ u32 **out, int *len, u32 size)
+{
+ int ret = 0;
+ struct device_node *np = dev->of_node;
+ size_t sz;
+ u32 *arr = NULL;
+
+ if (!of_get_property(np, prop_name, len)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ sz = *len = *len / sizeof(*arr);
+ if (sz <= 0 || (size > 0 && (sz != size))) {
+ dev_err(dev, "%s invalid size\n", prop_name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ arr = devm_kzalloc(dev, sz * sizeof(*arr), GFP_KERNEL);
+ if (!arr) {
+ dev_err(dev, "%s failed allocating memory\n", prop_name);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = of_property_read_u32_array(np, prop_name, arr, sz);
+ if (ret < 0) {
+ dev_err(dev, "%s failed reading array %d\n", prop_name, ret);
+ goto out;
+ }
+ *out = arr;
+out:
+ if (ret)
+ *len = 0;
+ return ret;
+}
+
#define MAX_PROP_SIZE 32
static int sdhci_msm_dt_parse_vreg_info(struct device *dev,
struct sdhci_msm_reg_data **vreg_data, const char *vreg_name)
@@ -261,11 +800,164 @@
return ret;
}
+/* GPIO/Pad data extraction */
+static int sdhci_msm_dt_get_pad_pull_info(struct device *dev, int id,
+ struct sdhci_msm_pad_pull_data **pad_pull_data)
+{
+ int ret = 0, base = 0, len, i;
+ u32 *tmp;
+ struct sdhci_msm_pad_pull_data *pull_data;
+ struct sdhci_msm_pad_pull *pull;
+
+ switch (id) {
+ case 1:
+ base = TLMM_PULL_SDC1_CLK;
+ break;
+ case 2:
+ base = TLMM_PULL_SDC2_CLK;
+ break;
+ case 3:
+ base = TLMM_PULL_SDC3_CLK;
+ break;
+ case 4:
+ base = TLMM_PULL_SDC4_CLK;
+ break;
+ default:
+ dev_err(dev, "%s: Invalid slot id\n", __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pull_data = devm_kzalloc(dev, sizeof(struct sdhci_msm_pad_pull_data),
+ GFP_KERNEL);
+ if (!pull_data) {
+ dev_err(dev, "No memory for msm_mmc_pad_pull_data\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+ pull_data->size = 3; /* array size for clk, cmd, data */
+
+ /* Allocate on, off configs for clk, cmd, data */
+ pull = devm_kzalloc(dev, 2 * pull_data->size *\
+ sizeof(struct sdhci_msm_pad_pull), GFP_KERNEL);
+ if (!pull) {
+ dev_err(dev, "No memory for msm_mmc_pad_pull\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+ pull_data->on = pull;
+ pull_data->off = pull + pull_data->size;
+
+ ret = sdhci_msm_dt_get_array(dev, "qcom,pad-pull-on",
+ &tmp, &len, pull_data->size);
+ if (ret)
+ goto out;
+
+ for (i = 0; i < len; i++) {
+ pull_data->on[i].no = base + i;
+ pull_data->on[i].val = tmp[i];
+ dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
+ i, pull_data->on[i].val);
+ }
+
+ ret = sdhci_msm_dt_get_array(dev, "qcom,pad-pull-off",
+ &tmp, &len, pull_data->size);
+ if (ret)
+ goto out;
+
+ for (i = 0; i < len; i++) {
+ pull_data->off[i].no = base + i;
+ pull_data->off[i].val = tmp[i];
+ dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
+ i, pull_data->off[i].val);
+ }
+
+ *pad_pull_data = pull_data;
+out:
+ return ret;
+}
+
+static int sdhci_msm_dt_get_pad_drv_info(struct device *dev, int id,
+ struct sdhci_msm_pad_drv_data **pad_drv_data)
+{
+ int ret = 0, base = 0, len, i;
+ u32 *tmp;
+ struct sdhci_msm_pad_drv_data *drv_data;
+ struct sdhci_msm_pad_drv *drv;
+
+ switch (id) {
+ case 1:
+ base = TLMM_HDRV_SDC1_CLK;
+ break;
+ case 2:
+ base = TLMM_HDRV_SDC2_CLK;
+ break;
+ case 3:
+ base = TLMM_HDRV_SDC3_CLK;
+ break;
+ case 4:
+ base = TLMM_HDRV_SDC4_CLK;
+ break;
+ default:
+ dev_err(dev, "%s: Invalid slot id\n", __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ drv_data = devm_kzalloc(dev, sizeof(struct sdhci_msm_pad_drv_data),
+ GFP_KERNEL);
+ if (!drv_data) {
+ dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+ drv_data->size = 3; /* array size for clk, cmd, data */
+
+ /* Allocate on, off configs for clk, cmd, data */
+ drv = devm_kzalloc(dev, 2 * drv_data->size *\
+ sizeof(struct sdhci_msm_pad_drv), GFP_KERNEL);
+ if (!drv) {
+ dev_err(dev, "No memory msm_mmc_pad_drv\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+ drv_data->on = drv;
+ drv_data->off = drv + drv_data->size;
+
+ ret = sdhci_msm_dt_get_array(dev, "qcom,pad-drv-on",
+ &tmp, &len, drv_data->size);
+ if (ret)
+ goto out;
+
+ for (i = 0; i < len; i++) {
+ drv_data->on[i].no = base + i;
+ drv_data->on[i].val = tmp[i];
+ dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
+ i, drv_data->on[i].val);
+ }
+
+ ret = sdhci_msm_dt_get_array(dev, "qcom,pad-drv-off",
+ &tmp, &len, drv_data->size);
+ if (ret)
+ goto out;
+
+ for (i = 0; i < len; i++) {
+ drv_data->off[i].no = base + i;
+ drv_data->off[i].val = tmp[i];
+ dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
+ i, drv_data->off[i].val);
+ }
+
+ *pad_drv_data = drv_data;
+out:
+ return ret;
+}
+
#define GPIO_NAME_MAX_LEN 32
static int sdhci_msm_dt_parse_gpio_info(struct device *dev,
struct sdhci_msm_pltfm_data *pdata)
{
- int ret = 0, cnt, i;
+ int ret = 0, id = 0, cnt, i;
struct sdhci_msm_pin_data *pin_data;
struct device_node *np = dev->of_node;
@@ -278,6 +970,7 @@
cnt = of_gpio_count(np);
if (cnt > 0) {
+ pin_data->is_gpio = true;
pin_data->gpio_data = devm_kzalloc(dev,
sizeof(struct sdhci_msm_gpio_data), GFP_KERNEL);
if (!pin_data->gpio_data) {
@@ -294,7 +987,6 @@
ret = -ENOMEM;
goto out;
}
-
for (i = 0; i < cnt; i++) {
const char *name = NULL;
char result[GPIO_NAME_MAX_LEN];
@@ -306,12 +998,39 @@
dev_name(dev), name ? name : "?");
pin_data->gpio_data->gpio[i].name = result;
dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
- pin_data->gpio_data->gpio[i].name,
- pin_data->gpio_data->gpio[i].no);
- pdata->pin_data = pin_data;
+ pin_data->gpio_data->gpio[i].name,
+ pin_data->gpio_data->gpio[i].no);
}
- }
+ } else {
+ pin_data->pad_data =
+ devm_kzalloc(dev,
+ sizeof(struct sdhci_msm_pad_data),
+ GFP_KERNEL);
+ if (!pin_data->pad_data) {
+ dev_err(dev,
+ "No memory for pin_data->pad_data\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+ ret = of_alias_get_id(np, "sdhc");
+ if (ret < 0) {
+ dev_err(dev, "Failed to get slot index %d\n", ret);
+ goto out;
+ }
+ id = ret;
+
+ ret = sdhci_msm_dt_get_pad_pull_info(
+ dev, id, &pin_data->pad_data->pull);
+ if (ret)
+ goto out;
+ ret = sdhci_msm_dt_get_pad_drv_info(
+ dev, id, &pin_data->pad_data->drv);
+ if (ret)
+ goto out;
+
+ }
+ pdata->pin_data = pin_data;
out:
if (ret)
dev_err(dev, "%s failed with err %d\n", __func__, ret);
@@ -665,7 +1384,9 @@
static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
{
- struct sdhci_msm_host *msm_host = (struct sdhci_msm_host *)data;
+ struct sdhci_host *host = (struct sdhci_host *)data;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
u8 irq_status = 0;
u8 irq_ack = 0;
int ret = 0;
@@ -731,6 +1452,16 @@
*/
mb();
+ if (irq_status & CORE_PWRCTL_IO_HIGH)
+ writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) &
+ ~CORE_IO_PAD_PWR_SWITCH),
+ host->ioaddr + CORE_VENDOR_SPEC);
+ if (irq_status & CORE_PWRCTL_IO_LOW)
+ writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) |
+ CORE_IO_PAD_PWR_SWITCH),
+ host->ioaddr + CORE_VENDOR_SPEC);
+ mb();
+
pr_debug("%s: Handled IRQ(%d), ret=%d, ack=0x%x\n",
mmc_hostname(msm_host->mmc), irq, ret, irq_ack);
wake_up_interruptible(&msm_host->pwr_irq_wait);
@@ -771,8 +1502,28 @@
readb_relaxed(msm_host->core_mem + CORE_PWRCTL_CTL));
}
+static void sdhci_msm_toggle_cdr(struct sdhci_host *host, bool enable)
+{
+ if (enable)
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ CORE_DLL_CONFIG) | CORE_CDR_EN),
+ host->ioaddr + CORE_DLL_CONFIG);
+ else
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ CORE_DLL_CONFIG) & ~CORE_CDR_EN),
+ host->ioaddr + CORE_DLL_CONFIG);
+}
+
+static unsigned int sdhci_msm_max_segs(void)
+{
+ return SDHCI_MSM_MAX_SEGMENTS;
+}
+
static struct sdhci_ops sdhci_msm_ops = {
.check_power_status = sdhci_msm_check_power_status,
+ .execute_tuning = sdhci_msm_execute_tuning,
+ .toggle_cdr = sdhci_msm_toggle_cdr,
+ .get_max_segments = sdhci_msm_max_segs,
};
static int __devinit sdhci_msm_probe(struct platform_device *pdev)
@@ -783,6 +1534,7 @@
struct resource *core_memres = NULL;
int ret = 0, pwr_irq = 0, dead = 0;
u32 vdd_max_current;
+ u32 host_version;
pr_debug("%s: Enter %s\n", dev_name(&pdev->dev), __func__);
msm_host = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_msm_host),
@@ -880,7 +1632,27 @@
*/
host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
host->quirks |= SDHCI_QUIRK_SINGLE_POWER_WRITE;
+ host->quirks2 |= SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING;
+ host_version = readl_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
+ dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n",
+ host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >>
+ SDHCI_VENDOR_VER_SHIFT));
+ if (((host_version & SDHCI_VENDOR_VER_MASK) >>
+ SDHCI_VENDOR_VER_SHIFT) == SDHCI_VER_100) {
+ /*
+ * Add 40us delay in interrupt handler when
+ * operating at initialization frequency(400KHz).
+ */
+ host->quirks2 |= SDHCI_QUIRK2_SLOW_INT_CLR;
+ /*
+ * Set Software Reset for DAT line in Software
+ * Reset Register (Bit 2).
+ */
+ host->quirks2 |= SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT;
+ }
+
+ /* Setup PWRCTL irq */
pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
if (pwr_irq < 0) {
dev_err(&pdev->dev, "Failed to get pwr_irq by name (%d)\n",
@@ -889,7 +1661,7 @@
}
ret = devm_request_threaded_irq(&pdev->dev, pwr_irq, NULL,
sdhci_msm_pwr_irq, IRQF_ONESHOT,
- dev_name(&pdev->dev), msm_host);
+ dev_name(&pdev->dev), host);
if (ret) {
dev_err(&pdev->dev, "Request threaded irq(%d) failed (%d)\n",
pwr_irq, ret);
@@ -918,6 +1690,7 @@
MMC_CAP_SET_XPC_300|
MMC_CAP_SET_XPC_330;
+ msm_host->mmc->caps |= MMC_CAP_HW_RESET;
msm_host->mmc->caps2 |= msm_host->pdata->caps2;
msm_host->mmc->caps2 |= MMC_CAP2_PACKED_WR;
msm_host->mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
@@ -990,7 +1763,7 @@
if (!IS_ERR_OR_NULL(msm_host->bus_clk))
clk_disable_unprepare(msm_host->bus_clk);
if (pdata->pin_data)
- sdhci_msm_setup_gpio(pdata, false);
+ sdhci_msm_setup_pins(pdata, false);
return 0;
}
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 8c2bea09..326f220 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -483,9 +483,10 @@
* The ADMA descriptor table is mapped further down as we
* need to fill it with data first.
*/
-
host->align_addr = dma_map_single(mmc_dev(host->mmc),
- host->align_buffer, 128 * 4, direction);
+ host->align_buffer,
+ host->align_buf_sz,
+ direction);
if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr))
goto fail;
BUG_ON(host->align_addr & 0x3);
@@ -544,7 +545,8 @@
* If this triggers then we have a calculation bug
* somewhere. :/
*/
- WARN_ON((desc - host->adma_desc) > (128 * 2 + 1) * 4);
+ WARN_ON((desc - host->adma_desc) > host->adma_desc_sz);
+
}
if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) {
@@ -569,11 +571,15 @@
*/
if (data->flags & MMC_DATA_WRITE) {
dma_sync_single_for_device(mmc_dev(host->mmc),
- host->align_addr, 128 * 4, direction);
+ host->align_addr,
+ host->align_buf_sz,
+ direction);
}
host->adma_addr = dma_map_single(mmc_dev(host->mmc),
- host->adma_desc, (128 * 2 + 1) * 4, DMA_TO_DEVICE);
+ host->adma_desc,
+ host->adma_desc_sz,
+ DMA_TO_DEVICE);
if (dma_mapping_error(mmc_dev(host->mmc), host->adma_addr))
goto unmap_entries;
BUG_ON(host->adma_addr & 0x3);
@@ -585,7 +591,7 @@
data->sg_len, direction);
unmap_align:
dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
- 128 * 4, direction);
+ host->align_buf_sz, direction);
fail:
return -EINVAL;
}
@@ -607,10 +613,10 @@
direction = DMA_TO_DEVICE;
dma_unmap_single(mmc_dev(host->mmc), host->adma_addr,
- (128 * 2 + 1) * 4, DMA_TO_DEVICE);
+ host->adma_desc_sz, DMA_TO_DEVICE);
dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
- 128 * 4, direction);
+ host->align_buf_sz, direction);
if (data->flags & MMC_DATA_READ) {
dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg,
@@ -721,7 +727,7 @@
return;
/* Sanity checks */
- BUG_ON(data->blksz * data->blocks > 524288);
+ BUG_ON(data->blksz * data->blocks > host->mmc->max_req_size);
BUG_ON(data->blksz > host->mmc->max_blk_size);
BUG_ON(data->blocks > 65535);
@@ -2049,6 +2055,9 @@
controllers do not like that. */
sdhci_reset(host, SDHCI_RESET_CMD);
sdhci_reset(host, SDHCI_RESET_DATA);
+ } else {
+ if (host->quirks2 & SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT)
+ sdhci_reset(host, SDHCI_RESET_DATA);
}
host->mrq = NULL;
@@ -2135,6 +2144,16 @@
SDHCI_INT_INDEX))
host->cmd->error = -EILSEQ;
+ if (host->quirks2 & SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING) {
+ if ((host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) ||
+ (host->cmd->opcode == MMC_SEND_TUNING_BLOCK)) {
+ if (intmask & SDHCI_INT_CRC) {
+ sdhci_reset(host, SDHCI_RESET_CMD);
+ host->cmd->error = 0;
+ }
+ }
+ }
+
if (host->cmd->error) {
tasklet_schedule(&host->finish_tasklet);
return;
@@ -2162,6 +2181,16 @@
* fall through and take the SDHCI_INT_RESPONSE */
}
+ if (host->quirks2 & SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING) {
+ if ((host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) ||
+ (host->cmd->opcode == MMC_SEND_TUNING_BLOCK)) {
+ if (intmask & SDHCI_INT_CRC) {
+ sdhci_finish_command(host);
+ return;
+ }
+ }
+ }
+
if (intmask & SDHCI_INT_RESPONSE)
sdhci_finish_command(host);
}
@@ -2349,12 +2378,18 @@
if (intmask & SDHCI_INT_CMD_MASK) {
sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK,
SDHCI_INT_STATUS);
+ if ((host->quirks2 & SDHCI_QUIRK2_SLOW_INT_CLR) &&
+ (host->clock <= 400000))
+ udelay(40);
sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
}
if (intmask & SDHCI_INT_DATA_MASK) {
sdhci_writel(host, intmask & SDHCI_INT_DATA_MASK,
SDHCI_INT_STATUS);
+ if ((host->quirks2 & SDHCI_QUIRK2_SLOW_INT_CLR) &&
+ (host->clock <= 400000))
+ udelay(40);
sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
}
@@ -2686,11 +2721,23 @@
if (host->flags & SDHCI_USE_ADMA) {
/*
* We need to allocate descriptors for all sg entries
- * (128) and potentially one alignment transfer for
+ * (128/max_segments) and potentially one alignment transfer for
* each of those entries.
*/
- host->adma_desc = kmalloc((128 * 2 + 1) * 4, GFP_KERNEL);
- host->align_buffer = kmalloc(128 * 4, GFP_KERNEL);
+ if (host->ops->get_max_segments)
+ host->adma_max_desc = host->ops->get_max_segments();
+ else
+ host->adma_max_desc = 128;
+
+ host->adma_desc_sz = (host->adma_max_desc * 2 + 1) * 4;
+ host->align_buf_sz = host->adma_max_desc * 4;
+
+ pr_debug("%s: %s: dma_desc_size: %d\n",
+ mmc_hostname(host->mmc), __func__, host->adma_desc_sz);
+ host->adma_desc = kmalloc(host->adma_desc_sz,
+ GFP_KERNEL);
+ host->align_buffer = kmalloc(host->align_buf_sz,
+ GFP_KERNEL);
if (!host->adma_desc || !host->align_buffer) {
kfree(host->adma_desc);
kfree(host->align_buffer);
@@ -2944,17 +2991,21 @@
* can do scatter/gather or not.
*/
if (host->flags & SDHCI_USE_ADMA)
- mmc->max_segs = 128;
+ mmc->max_segs = host->adma_max_desc;
else if (host->flags & SDHCI_USE_SDMA)
mmc->max_segs = 1;
- else /* PIO */
- mmc->max_segs = 128;
+ else/* PIO */
+ mmc->max_segs = host->adma_max_desc;
/*
* Maximum number of sectors in one transfer. Limited by DMA boundary
- * size (512KiB).
+ * size (512KiB), unless specified by platform specific driver. Each
+ * descriptor can transfer a maximum of 64KB.
*/
- mmc->max_req_size = 524288;
+ if (host->ops->get_max_segments)
+ mmc->max_req_size = (host->adma_max_desc * 65536);
+ else
+ mmc->max_req_size = 524288;
/*
* Maximum segment size. Could be one segment with the maximum number
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 4f8d01d..c0ae39f 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -280,6 +280,7 @@
void (*check_power_status)(struct sdhci_host *host);
int (*execute_tuning)(struct sdhci_host *host, u32 opcode);
void (*toggle_cdr)(struct sdhci_host *host, bool enable);
+ unsigned int (*get_max_segments)(void);
};
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index ed4e246..867aec1 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -58,16 +58,35 @@
#define MSM_RIVA_CCU_BASE 0x03200800
-#define CCU_INVALID_ADDR_OFFSET 0x100
-#define CCU_LAST_ADDR0_OFFSET 0x104
-#define CCU_LAST_ADDR1_OFFSET 0x108
-#define CCU_LAST_ADDR2_OFFSET 0x10c
+#define CCU_RIVA_INVALID_ADDR_OFFSET 0x100
+#define CCU_RIVA_LAST_ADDR0_OFFSET 0x104
+#define CCU_RIVA_LAST_ADDR1_OFFSET 0x108
+#define CCU_RIVA_LAST_ADDR2_OFFSET 0x10c
#define MSM_PRONTO_A2XB_BASE 0xfb100400
-#define A2XB_CFG_OFFSET 0x00
-#define A2XB_INT_SRC_OFFSET 0x0c
+#define A2XB_CFG_OFFSET 0x00
+#define A2XB_INT_SRC_OFFSET 0x0c
+#define A2XB_TSTBUS_CTRL_OFFSET 0x14
+#define A2XB_TSTBUS_OFFSET 0x18
#define A2XB_ERR_INFO_OFFSET 0x1c
+#define WCNSS_TSTBUS_CTRL_EN BIT(0)
+#define WCNSS_TSTBUS_CTRL_AXIM (0x02 << 1)
+#define WCNSS_TSTBUS_CTRL_CMDFIFO (0x03 << 1)
+#define WCNSS_TSTBUS_CTRL_WRFIFO (0x04 << 1)
+#define WCNSS_TSTBUS_CTRL_RDFIFO (0x05 << 1)
+#define WCNSS_TSTBUS_CTRL_CTRL (0x07 << 1)
+#define WCNSS_TSTBUS_CTRL_AXIM_CFG0 (0x00 << 6)
+#define WCNSS_TSTBUS_CTRL_AXIM_CFG1 (0x01 << 6)
+#define WCNSS_TSTBUS_CTRL_CTRL_CFG0 (0x00 << 12)
+#define WCNSS_TSTBUS_CTRL_CTRL_CFG1 (0x01 << 12)
+
+#define MSM_PRONTO_CCPU_BASE 0xfb205050
+#define CCU_PRONTO_INVALID_ADDR_OFFSET 0x08
+#define CCU_PRONTO_LAST_ADDR0_OFFSET 0x0c
+#define CCU_PRONTO_LAST_ADDR1_OFFSET 0x10
+#define CCU_PRONTO_LAST_ADDR2_OFFSET 0x14
+
#define WCNSS_CTRL_CHANNEL "WCNSS_CTRL"
#define WCNSS_MAX_FRAME_SIZE 500
#define WCNSS_VERSION_LEN 30
@@ -173,6 +192,7 @@
void __iomem *msm_wcnss_base;
void __iomem *riva_ccu_base;
void __iomem *pronto_a2xb_base;
+ void __iomem *pronto_ccpu_base;
} *penv = NULL;
static ssize_t wcnss_serial_number_show(struct device *dev,
@@ -253,19 +273,19 @@
void __iomem *ccu_reg;
u32 reg = 0;
- ccu_reg = penv->riva_ccu_base + CCU_INVALID_ADDR_OFFSET;
+ ccu_reg = penv->riva_ccu_base + CCU_RIVA_INVALID_ADDR_OFFSET;
reg = readl_relaxed(ccu_reg);
pr_info_ratelimited("%s: CCU_CCPU_INVALID_ADDR %08x\n", __func__, reg);
- ccu_reg = penv->riva_ccu_base + CCU_LAST_ADDR0_OFFSET;
+ ccu_reg = penv->riva_ccu_base + CCU_RIVA_LAST_ADDR0_OFFSET;
reg = readl_relaxed(ccu_reg);
pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR0 %08x\n", __func__, reg);
- ccu_reg = penv->riva_ccu_base + CCU_LAST_ADDR1_OFFSET;
+ ccu_reg = penv->riva_ccu_base + CCU_RIVA_LAST_ADDR1_OFFSET;
reg = readl_relaxed(ccu_reg);
pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR1 %08x\n", __func__, reg);
- ccu_reg = penv->riva_ccu_base + CCU_LAST_ADDR2_OFFSET;
+ ccu_reg = penv->riva_ccu_base + CCU_RIVA_LAST_ADDR2_OFFSET;
reg = readl_relaxed(ccu_reg);
pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
@@ -275,7 +295,7 @@
/* Log pronto debug registers before sending reset interrupt */
void wcnss_pronto_log_debug_regs(void)
{
- void __iomem *reg_addr;
+ void __iomem *reg_addr, *tst_addr, *tst_ctrl_addr;
u32 reg = 0;
reg_addr = penv->pronto_a2xb_base + A2XB_CFG_OFFSET;
@@ -290,6 +310,84 @@
reg = readl_relaxed(reg_addr);
pr_info_ratelimited("%s: A2XB_ERR_INFO_OFFSET %08x\n", __func__, reg);
+ reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_INVALID_ADDR_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_info_ratelimited("%s: CCU_CCPU_INVALID_ADDR %08x\n", __func__, reg);
+
+ reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR0_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR0 %08x\n", __func__, reg);
+
+ reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR1_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR1 %08x\n", __func__, reg);
+
+ reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR2_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
+
+ tst_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_OFFSET;
+ tst_ctrl_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_CTRL_OFFSET;
+
+ /* read data FIFO */
+ reg = 0;
+ reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_RDFIFO;
+ writel_relaxed(reg, tst_ctrl_addr);
+ reg = readl_relaxed(tst_addr);
+ pr_info_ratelimited("%s: Read data FIFO testbus %08x\n",
+ __func__, reg);
+
+ /* command FIFO */
+ reg = 0;
+ reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_CMDFIFO;
+ writel_relaxed(reg, tst_ctrl_addr);
+ reg = readl_relaxed(tst_addr);
+ pr_info_ratelimited("%s: Command FIFO testbus %08x\n",
+ __func__, reg);
+
+ /* write data FIFO */
+ reg = 0;
+ reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_WRFIFO;
+ writel_relaxed(reg, tst_ctrl_addr);
+ reg = readl_relaxed(tst_addr);
+ pr_info_ratelimited("%s: Rrite data FIFO testbus %08x\n",
+ __func__, reg);
+
+ /* AXIM SEL CFG0 */
+ reg = 0;
+ reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_AXIM |
+ WCNSS_TSTBUS_CTRL_AXIM_CFG0;
+ writel_relaxed(reg, tst_ctrl_addr);
+ reg = readl_relaxed(tst_addr);
+ pr_info_ratelimited("%s: AXIM SEL CFG0 testbus %08x\n",
+ __func__, reg);
+
+ /* AXIM SEL CFG1 */
+ reg = 0;
+ reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_AXIM |
+ WCNSS_TSTBUS_CTRL_AXIM_CFG1;
+ writel_relaxed(reg, tst_ctrl_addr);
+ reg = readl_relaxed(tst_addr);
+ pr_info_ratelimited("%s: AXIM SEL CFG1 testbus %08x\n",
+ __func__, reg);
+
+ /* CTRL SEL CFG0 */
+ reg = 0;
+ reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_CTRL |
+ WCNSS_TSTBUS_CTRL_CTRL_CFG0;
+ writel_relaxed(reg, tst_ctrl_addr);
+ reg = readl_relaxed(tst_addr);
+ pr_info_ratelimited("%s: CTRL SEL CFG0 testbus %08x\n",
+ __func__, reg);
+
+ /* CTRL SEL CFG1 */
+ reg = 0;
+ reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_CTRL |
+ WCNSS_TSTBUS_CTRL_CTRL_CFG1;
+ writel_relaxed(reg, tst_ctrl_addr);
+ reg = readl_relaxed(tst_addr);
+ pr_info_ratelimited("%s: CTRL SEL CFG1 testbus %08x\n", __func__, reg);
+
}
EXPORT_SYMBOL(wcnss_pronto_log_debug_regs);
@@ -1071,11 +1169,19 @@
pr_err("%s: ioremap wcnss physical failed\n", __func__);
goto fail_ioremap;
}
+ penv->pronto_ccpu_base = ioremap(MSM_PRONTO_CCPU_BASE, SZ_512);
+ if (!penv->pronto_ccpu_base) {
+ ret = -ENOMEM;
+ pr_err("%s: ioremap wcnss physical failed\n", __func__);
+ goto fail_ioremap2;
+ }
}
penv->cold_boot_done = 1;
return 0;
+fail_ioremap2:
+ iounmap(penv->pronto_a2xb_base);
fail_ioremap:
iounmap(penv->msm_wcnss_base);
fail_wake:
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index edf3a60..1142094 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -161,6 +161,7 @@
struct ipa_ioc_nat_alloc_mem nat_mem;
struct ipa_ioc_v4_nat_init nat_init;
struct ipa_ioc_v4_nat_del nat_del;
+ struct ipa_ioc_rm_dependency rm_depend;
size_t sz;
IPADBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd));
@@ -593,6 +594,24 @@
break;
}
break;
+ case IPA_IOC_RM_ADD_DEPENDENCY:
+ if (copy_from_user((u8 *)&rm_depend, (u8 *)arg,
+ sizeof(struct ipa_ioc_rm_dependency))) {
+ retval = -EFAULT;
+ break;
+ }
+ retval = ipa_rm_add_dependency(rm_depend.resource_name,
+ rm_depend.depends_on_name);
+ break;
+ case IPA_IOC_RM_DEL_DEPENDENCY:
+ if (copy_from_user((u8 *)&rm_depend, (u8 *)arg,
+ sizeof(struct ipa_ioc_rm_dependency))) {
+ retval = -EFAULT;
+ break;
+ }
+ retval = ipa_rm_delete_dependency(rm_depend.resource_name,
+ rm_depend.depends_on_name);
+ break;
default: /* redundant, as cmd was checked against MAXNR */
return -ENOTTY;
}
diff --git a/drivers/platform/msm/ipa/ipa_rm.c b/drivers/platform/msm/ipa/ipa_rm.c
index 99b19cc..1fdd300 100644
--- a/drivers/platform/msm/ipa/ipa_rm.c
+++ b/drivers/platform/msm/ipa/ipa_rm.c
@@ -48,7 +48,7 @@
if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
create_params->name,
&resource) == 0) {
- result = -EPERM;
+ result = -EEXIST;
goto bail;
}
result = ipa_rm_resource_create(create_params,
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c
index 3ba8e84..0a6771c 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.c
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.c
@@ -451,7 +451,7 @@
resource->name,
depends_on->peers_list,
depends_on->name))
- return -EINVAL;
+ return -EEXIST;
ipa_rm_peers_list_add_peer(resource->peers_list, depends_on);
ipa_rm_peers_list_add_peer(depends_on->peers_list, resource);
spin_lock_irqsave(&resource->state_lock, flags);
@@ -507,7 +507,7 @@
unsigned long flags;
if (!resource || !depends_on)
return -EINVAL;
- if (ipa_rm_peers_list_check_dependency(resource->peers_list,
+ if (!ipa_rm_peers_list_check_dependency(resource->peers_list,
resource->name,
depends_on->peers_list,
depends_on->name))
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index c841575..a9a850c 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -472,6 +472,63 @@
return 0;
}
+static void usb_prod_notify_cb(void *user_data, enum ipa_rm_event event,
+ unsigned long data)
+{
+ switch (event) {
+ case IPA_RM_RESOURCE_GRANTED:
+ pr_debug("USB_PROD resource granted\n");
+ break;
+ case IPA_RM_RESOURCE_RELEASED:
+ pr_debug("USB_PROD resource released\n");
+ break;
+ default:
+ break;
+ }
+ return;
+}
+
+static int usb_cons_request_resource(void)
+{
+ pr_debug(": Requesting USB_CONS resource\n");
+ return 0;
+}
+
+static int usb_cons_release_resource(void)
+{
+ pr_debug(": Releasing USB_CONS resource\n");
+ return 0;
+}
+
+static void usb_bam_ipa_create_resources(void)
+{
+ struct ipa_rm_create_params usb_prod_create_params;
+ struct ipa_rm_create_params usb_cons_create_params;
+ int ret;
+
+ /* Create USB_PROD entity */
+ memset(&usb_prod_create_params, 0, sizeof(usb_prod_create_params));
+ usb_prod_create_params.name = IPA_RM_RESOURCE_USB_PROD;
+ usb_prod_create_params.reg_params.notify_cb = usb_prod_notify_cb;
+ usb_prod_create_params.reg_params.user_data = NULL;
+ ret = ipa_rm_create_resource(&usb_prod_create_params);
+ if (ret) {
+ pr_err("%s: Failed to create USB_PROD resource\n", __func__);
+ return;
+ }
+
+ /* Create USB_CONS entity */
+ memset(&usb_cons_create_params, 0, sizeof(usb_cons_create_params));
+ usb_cons_create_params.name = IPA_RM_RESOURCE_USB_CONS;
+ usb_cons_create_params.request_resource = usb_cons_request_resource;
+ usb_cons_create_params.release_resource = usb_cons_release_resource;
+ ret = ipa_rm_create_resource(&usb_cons_create_params);
+ if (ret) {
+ pr_err("%s: Failed to create USB_CONS resource\n", __func__);
+ return ;
+ }
+}
+
int usb_bam_connect_ipa(struct usb_bam_connect_ipa_params *ipa_params)
{
u8 idx = ipa_params->idx;
@@ -500,6 +557,8 @@
connection->idx = idx;
+ ipa_rm_request_resource(IPA_CLIENT_USB_PROD);
+
ret = connect_pipe_ipa(ipa_params);
if (ret) {
pr_err("%s: dst pipe connection failure\n", __func__);
@@ -779,6 +838,7 @@
}
}
+ ipa_rm_release_resource(IPA_CLIENT_USB_PROD);
return 0;
}
@@ -925,14 +985,6 @@
return 0;
}
-static u8 qdss_conn_num;
-
-u8 usb_bam_get_qdss_num(void)
-{
- return qdss_conn_num;
-}
-EXPORT_SYMBOL(usb_bam_get_qdss_num);
-
static struct msm_usb_bam_platform_data *usb_bam_dt_to_pdata(
struct platform_device *pdev)
{
@@ -1055,11 +1107,6 @@
!strcmp(str, "usb-to-peri-qdss-hsusb") ||
!strcmp(str, "peri-to-usb-qdss-hsusb"))
conn_num = 0;
- else if (!strcmp(str, "usb-to-qdss-hsusb") ||
- !strcmp(str, "qdss-to-usb-hsusb")) {
- conn_num = 1;
- qdss_conn_num = 1;
- }
else
goto err;
@@ -1094,8 +1141,6 @@
struct resource *res, *ram_resource;
int irq;
- qdss_conn_num = 0;
-
res = platform_get_resource_byname(usb_bam_pdev, IORESOURCE_MEM,
bam_enable_strings[pdata->usb_active_bam]);
if (!res) {
@@ -1276,6 +1321,8 @@
return -ENOMEM;
}
+ usb_bam_ipa_create_resources();
+
return ret;
}
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 482d383..b04213c 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -616,7 +616,8 @@
calib_data[5] = readl_relaxed(
(TSENS_EEPROM_8X26_2(tmdev->tsens_calib_addr)) + 0x8);
- tsens_calibration_mode = calib_data[5] & TSENS_8X26_TSENS_CAL_SEL;
+ tsens_calibration_mode = (calib_data[5] & TSENS_8X26_TSENS_CAL_SEL)
+ >> TSENS_8X26_CAL_SEL_SHIFT;
if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) ||
(tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) {
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index f38de0c..65b2199 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -1963,7 +1963,7 @@
(mdwc->ext_xceiv.otg_capability || !init)) {
mdwc->ext_xceiv.bsv = val->intval;
queue_delayed_work(system_nrt_wq,
- &mdwc->resume_work, 0);
+ &mdwc->resume_work, 20);
if (!init)
init = true;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 5694999..f060718 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1567,6 +1567,8 @@
return ret;
}
+static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc);
+
static int dwc3_gadget_vbus_session(struct usb_gadget *_gadget, int is_active)
{
struct dwc3 *dwc = gadget_to_dwc(_gadget);
@@ -1597,17 +1599,18 @@
} else {
ret = dwc3_gadget_run_stop(dwc, 0);
}
- } else if (dwc->gadget_driver && !dwc->softconnect &&
- !dwc->vbus_active) {
- if (dwc->gadget_driver->disconnect) {
- spin_unlock_irqrestore(&dwc->lock, flags);
- dwc->gadget_driver->disconnect(&dwc->gadget);
- return 0;
- }
+ }
+
+ /*
+ * Clearing run/stop bit might occur before disconnect event is seen.
+ * Make sure to let gadget driver know in that case.
+ */
+ if (!dwc->vbus_active && dwc->start_config_issued) {
+ dev_dbg(dwc->dev, "calling disconnect from %s\n", __func__);
+ dwc3_gadget_disconnect_interrupt(dwc);
}
spin_unlock_irqrestore(&dwc->lock, flags);
-
return ret;
}
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index a2997e9..5a6faf2 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -667,7 +667,7 @@
if (ret)
pr_err("%s: usb_bam_disconnect_ipa failed: err:%d\n",
__func__, ret);
- rmnet_bridge_disconnect();
+ teth_bridge_disconnect();
}
}
@@ -707,8 +707,11 @@
static void gbam2bam_connect_work(struct work_struct *w)
{
struct gbam_port *port = container_of(w, struct gbam_port, connect_w);
+ struct teth_bridge_connect_params connect_params;
struct bam_ch_info *d = &port->data_ch;
u32 sps_params;
+ ipa_notify_cb usb_notify_cb;
+ void *priv;
int ret;
if (d->trans == USB_GADGET_XPORT_BAM2BAM) {
@@ -720,6 +723,15 @@
return;
}
} else if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+ ret = teth_bridge_init(&usb_notify_cb, &priv);
+ if (ret) {
+ pr_err("%s:teth_bridge_init() failed\n", __func__);
+ return;
+ }
+ d->ipa_params.notify = usb_notify_cb;
+ d->ipa_params.priv = priv;
+ d->ipa_params.ipa_ep_cfg.mode.mode = IPA_BASIC;
+
d->ipa_params.client = IPA_CLIENT_USB_CONS;
d->ipa_params.dir = PEER_PERIPHERAL_TO_USB;
ret = usb_bam_connect_ipa(&d->ipa_params);
@@ -731,18 +743,21 @@
d->ipa_params.client = IPA_CLIENT_USB_PROD;
d->ipa_params.dir = USB_TO_PEER_PERIPHERAL;
- /* Currently only DMA mode is supported */
- d->ipa_params.ipa_ep_cfg.mode.mode = IPA_DMA;
- d->ipa_params.ipa_ep_cfg.mode.dst =
- IPA_CLIENT_A2_TETHERED_CONS;
ret = usb_bam_connect_ipa(&d->ipa_params);
if (ret) {
pr_err("%s: usb_bam_connect_ipa failed: err:%d\n",
__func__, ret);
return;
}
- rmnet_bridge_connect(d->ipa_params.prod_clnt_hdl,
- d->ipa_params.cons_clnt_hdl, 0);
+
+ connect_params.ipa_usb_pipe_hdl = d->ipa_params.prod_clnt_hdl;
+ connect_params.usb_ipa_pipe_hdl = d->ipa_params.cons_clnt_hdl;
+ connect_params.tethering_mode = TETH_TETHERING_MODE_RMNET;
+ ret = teth_bridge_connect(&connect_params);
+ if (ret) {
+ pr_err("%s:teth_bridge_connect() failed\n", __func__);
+ return;
+ }
}
d->rx_req = usb_ep_alloc_request(port->port_usb->out, GFP_KERNEL);
diff --git a/drivers/usb/gadget/u_qdss.c b/drivers/usb/gadget/u_qdss.c
index 2931ace..028d5e6 100644
--- a/drivers/usb/gadget/u_qdss.c
+++ b/drivers/usb/gadget/u_qdss.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -15,6 +15,8 @@
#include <linux/usb/msm_hsusb.h>
#include <mach/usb_bam.h>
+#define BAM_CONNC_IDX 0 /* USB bam connection index */
+
struct usb_qdss_bam_connect_info {
u32 usb_bam_pipe_idx;
u32 peer_pipe_idx;
@@ -55,18 +57,17 @@
pr_err("send_sps_req: usb_ep_queue error\n");
return -EIO;
}
-
return 0;
}
int set_qdss_data_connection(struct usb_ep *data_ep, u8 data_addr, int enable)
{
int res = 0;
- u8 conn_num = usb_bam_get_qdss_num();
+
pr_debug("set_qdss_data_connection\n");
if (enable) {
- res = usb_bam_connect(conn_num, NULL,
+ res = usb_bam_connect(BAM_CONNC_IDX, NULL,
&(bam_info.usb_bam_pipe_idx));
if (res) {
pr_err("usb_bam_connection error\n");
@@ -79,7 +80,7 @@
pr_err("qdss_data_connection: memory alloc failed\n");
return -ENOMEM;
}
- get_bam2bam_connection_info(conn_num,
+ get_bam2bam_connection_info(BAM_CONNC_IDX,
PEER_PERIPHERAL_TO_USB, &bam_info.usb_bam_handle,
&bam_info.usb_bam_pipe_idx, &bam_info.peer_pipe_idx,
NULL, bam_info.data_fifo);
@@ -88,7 +89,7 @@
bam_info.data_fifo->size, bam_info.usb_bam_pipe_idx);
} else {
kfree(bam_info.data_fifo);
- res = usb_bam_disconnect_pipe(conn_num);
+ res = usb_bam_disconnect_pipe(BAM_CONNC_IDX);
if (res) {
pr_err("usb_bam_disconnection error\n");
return res;
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index f1f6962..ea5484b 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -1776,6 +1776,9 @@
pdata->bus_scale_table = msm_bus_cl_get_pdata(pdev);
+ pdata->pool_64_bit_align = of_property_read_bool(node,
+ "qcom,pool-64-bit-align");
+
return pdata;
}
@@ -1853,6 +1856,7 @@
mehci->ehci.reset_sof_bug = 1;
mehci->ehci.resume_sof_bug = 1;
+ mehci->ehci.pool_64_bit_align = pdata->pool_64_bit_align;
if (pdata)
mehci->ehci.log2_irq_thresh = pdata->log2_irq_thresh;
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index 07a232a..d238b4e2 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -30,7 +30,6 @@
hcd->has_tt = pdata->has_tt;
ehci->has_synopsys_hc_bug = pdata->has_synopsys_hc_bug;
- ehci->pool_64_bit_align = pdata->pool_64_bit_align;
ehci->big_endian_desc = pdata->big_endian_desc;
ehci->big_endian_mmio = pdata->big_endian_mmio;
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index c03ca69..b35d904 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -3038,7 +3038,7 @@
set_bit(A_SRP_DET, &motg->inputs);
set_bit(A_BUS_REQ, &motg->inputs);
work = 1;
- } else if (otgsc & OTGSC_BSVIS) {
+ } else if ((otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) {
writel_relaxed(otgsc, USB_OTGSC);
/*
* BSV interrupt comes when operating as an A-device
@@ -3157,7 +3157,15 @@
static bool init;
struct msm_otg *motg = the_msm_otg;
- /* Ignore received BSV interrupts, if ID pin is GND */
+ if (online) {
+ pr_debug("PMIC: BSV set\n");
+ set_bit(B_SESS_VLD, &motg->inputs);
+ } else {
+ pr_debug("PMIC: BSV clear\n");
+ clear_bit(B_SESS_VLD, &motg->inputs);
+ }
+
+ /* do not queue state m/c work if id is grounded */
if (!test_bit(ID, &motg->inputs)) {
/*
* state machine work waits for initial VBUS
@@ -3166,17 +3174,8 @@
*/
if (init)
return;
- goto complete;
}
- if (online) {
- pr_debug("PMIC: BSV set\n");
- set_bit(B_SESS_VLD, &motg->inputs);
- } else {
- pr_debug("PMIC: BSV clear\n");
- clear_bit(B_SESS_VLD, &motg->inputs);
- }
-complete:
if (!init) {
init = true;
complete(&pmic_vbus_init);
@@ -3795,6 +3794,8 @@
"qcom,hsusb-otg-lpm-on-dev-suspend");
pdata->core_clk_always_on_workaround = of_property_read_bool(node,
"qcom,hsusb-otg-clk-always-on-workaround");
+ pdata->delay_lpm_on_disconnect = of_property_read_bool(node,
+ "qcom,hsusb-otg-delay-lpm");
return pdata;
}
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index bde7340..1c8664c 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -379,7 +379,7 @@
list_add_tail(&urb->urb_list, &portdata->in_urb_list);
spin_unlock_irqrestore(&portdata->in_lock, flags);
- schedule_work(&portdata->in_work);
+ queue_work(system_nrt_wq, &portdata->in_work);
return;
}
@@ -498,7 +498,7 @@
port->throttle_req = false;
port->throttled = false;
- schedule_work(&portdata->in_work);
+ queue_work(system_nrt_wq, &portdata->in_work);
}
EXPORT_SYMBOL(usb_wwan_unthrottle);
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index e4099ad..977fc63 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -124,6 +124,7 @@
char *prop_name, u32 *offsets, int len);
static int mdss_mdp_parse_dt_prop_len(struct platform_device *pdev,
char *prop_name);
+static int mdss_mdp_parse_dt_smp(struct platform_device *pdev);
static inline int mdss_irq_dispatch(u32 hw_ndx, int irq, void *ptr)
{
@@ -808,10 +809,6 @@
mdata->clk_ctrl_wq = create_singlethread_workqueue("mdp_clk_wq");
INIT_WORK(&mdata->clk_ctrl_worker, mdss_mdp_clk_ctrl_workqueue_handler);
- mdata->smp_mb_cnt = MDSS_MDP_SMP_MMB_BLOCKS;
- mdata->smp_mb_size = MDSS_MDP_SMP_MMB_SIZE;
-
-
mdata->iclient = msm_ion_client_create(-1, mdata->pdev->name);
if (IS_ERR_OR_NULL(mdata->iclient)) {
pr_err("msm_ion_client_create() return error (%p)\n",
@@ -1045,6 +1042,12 @@
return rc;
}
+ rc = mdss_mdp_parse_dt_smp(pdev);
+ if (rc) {
+ pr_err("Error in device tree : smp\n");
+ return rc;
+ }
+
return 0;
}
@@ -1305,6 +1308,30 @@
return rc;
}
+static int mdss_mdp_parse_dt_smp(struct platform_device *pdev)
+{
+ struct mdss_data_type *mdata = platform_get_drvdata(pdev);
+ u32 num;
+ u32 data[2];
+ int rc;
+
+ num = mdss_mdp_parse_dt_prop_len(pdev, "qcom,mdss-smp-data");
+
+ if (num != 2)
+ return -EINVAL;
+
+ rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-smp-data", data, num);
+ if (rc)
+ return rc;
+
+ rc = mdss_mdp_smp_setup(mdata, data[0], data[1]);
+
+ if (rc)
+ pr_err("unable to setup smp data\n");
+
+ return rc;
+}
+
static int mdss_mdp_parse_dt_handler(struct platform_device *pdev,
char *prop_name, u32 *offsets, int len)
{
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index e4f78ad..efd93c0 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -355,6 +355,7 @@
int mdss_mdp_pipe_pp_setup(struct mdss_mdp_pipe *pipe, u32 *op);
int mdss_mdp_pipe_sspp_setup(struct mdss_mdp_pipe *pipe, u32 *op);
void mdss_mdp_pipe_sspp_term(struct mdss_mdp_pipe *pipe);
+int mdss_mdp_smp_setup(struct mdss_data_type *mdata, u32 cnt, u32 size);
int mdss_hw_init(struct mdss_data_type *mdata);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index cabb183..8515782 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -39,6 +39,8 @@
static DEFINE_MUTEX(mdss_mdp_ctl_lock);
+static int mdss_mdp_mixer_free(struct mdss_mdp_mixer *mixer);
+
static inline void mdp_mixer_write(struct mdss_mdp_mixer *mixer,
u32 reg, u32 val)
{
@@ -265,8 +267,14 @@
mutex_lock(&mdss_mdp_ctl_lock);
ctl->ref_cnt--;
- ctl->mixer_left = NULL;
- ctl->mixer_right = NULL;
+ if (ctl->mixer_left) {
+ mdss_mdp_mixer_free(ctl->mixer_left);
+ ctl->mixer_left = NULL;
+ }
+ if (ctl->mixer_right) {
+ mdss_mdp_mixer_free(ctl->mixer_right);
+ ctl->mixer_right = NULL;
+ }
ctl->power_on = false;
ctl->start_fnc = NULL;
ctl->stop_fnc = NULL;
@@ -517,6 +525,50 @@
return 0;
}
+static int mdss_mdp_ctl_setup_wfd(struct mdss_mdp_ctl *ctl)
+{
+ struct mdss_data_type *mdata = ctl->mdata;
+ struct mdss_mdp_mixer *mixer;
+ int mixer_type;
+
+ /* if WB2 is supported, try to allocate it first */
+ if (mdata->nmixers_intf >= MDSS_MDP_INTF_LAYERMIXER2)
+ mixer_type = MDSS_MDP_MIXER_TYPE_INTF;
+ else
+ mixer_type = MDSS_MDP_MIXER_TYPE_WRITEBACK;
+
+ mixer = mdss_mdp_mixer_alloc(ctl, mixer_type, false);
+ if (!mixer && mixer_type == MDSS_MDP_MIXER_TYPE_INTF)
+ mixer = mdss_mdp_mixer_alloc(ctl, MDSS_MDP_MIXER_TYPE_WRITEBACK,
+ false);
+
+ if (!mixer) {
+ pr_err("Unable to allocate writeback mixer\n");
+ return -ENOMEM;
+ }
+
+ if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
+ ctl->opmode = MDSS_MDP_CTL_OP_WFD_MODE;
+ } else {
+ switch (mixer->num) {
+ case MDSS_MDP_WB_LAYERMIXER0:
+ ctl->opmode = MDSS_MDP_CTL_OP_WB0_MODE;
+ break;
+ case MDSS_MDP_WB_LAYERMIXER1:
+ ctl->opmode = MDSS_MDP_CTL_OP_WB1_MODE;
+ break;
+ default:
+ pr_err("Incorrect writeback config num=%d\n",
+ mixer->num);
+ mdss_mdp_mixer_free(mixer);
+ return -EINVAL;
+ }
+ }
+ ctl->mixer_left = mixer;
+
+ return 0;
+}
+
struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata,
struct msm_fb_data_type *mfd)
{
@@ -555,8 +607,10 @@
break;
case WRITEBACK_PANEL:
ctl->intf_num = MDSS_MDP_NO_INTF;
- ctl->opmode = MDSS_MDP_CTL_OP_WFD_MODE;
ctl->start_fnc = mdss_mdp_writeback_start;
+ ret = mdss_mdp_ctl_setup_wfd(ctl);
+ if (ret)
+ goto ctl_init_fail;
break;
default:
pr_err("unsupported panel type (%d)\n", pdata->panel_info.type);
@@ -966,9 +1020,13 @@
ctl->flush_bits |= BIT(6) << mixer->num; /* LAYER_MIXER */
- off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
mdp_mixer_write(mixer, MDSS_MDP_REG_LM_OP_MODE, blend_color_out);
- mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(mixer->num), mixercfg);
+ if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF)
+ off = MDSS_MDP_REG_CTL_LAYER(mixer->num);
+ else
+ off = MDSS_MDP_REG_CTL_LAYER(mixer->num +
+ MDSS_MDP_INTF_MAX_LAYERMIXER);
+ mdss_mdp_ctl_write(ctl, off, mixercfg);
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index d4ffaff..f8cd0ce 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -447,8 +447,7 @@
#define MDSS_MDP_REG_SMP_ALLOC_W0 0x00180
#define MDSS_MDP_REG_SMP_ALLOC_R0 0x00230
-#define MDSS_MDP_SMP_MMB_SIZE 4096
-#define MDSS_MDP_SMP_MMB_BLOCKS 22
+#define MDSS_MDP_SMP_MMB_BLOCKS 22
enum mdss_mdp_smp_client_index {
MDSS_MDP_SMP_CLIENT_UNUSED,
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index daa2499..dcefc09 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -654,10 +654,8 @@
ret = mdss_mdp_display_commit(ctl, NULL);
mutex_unlock(&mfd->lock);
- if (IS_ERR_VALUE(ret)) {
- mutex_unlock(&mfd->ov_lock);
- return ret;
- }
+ if (IS_ERR_VALUE(ret))
+ goto commit_fail;
ret = mdss_mdp_display_wait4comp(ctl);
@@ -670,6 +668,7 @@
add_timer(&mfd->no_update.timer);
mutex_unlock(&mfd->no_update.lock);
+commit_fail:
ret = mdss_mdp_overlay_cleanup(mfd);
mutex_unlock(&mfd->ov_lock);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 8c88646..d51b144 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -130,6 +130,17 @@
return 0;
}
+int mdss_mdp_smp_setup(struct mdss_data_type *mdata, u32 cnt, u32 size)
+{
+ if (!mdata)
+ return -EINVAL;
+
+ mdata->smp_mb_cnt = cnt;
+ mdata->smp_mb_size = size;
+
+ return 0;
+}
+
void mdss_mdp_pipe_unmap(struct mdss_mdp_pipe *pipe)
{
int tmp;
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index e9051e1..9fb01f4 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -91,6 +91,20 @@
unsigned int quirks2; /* More deviations from spec. */
#define SDHCI_QUIRK2_HOST_OFF_CARD_ON (1<<0)
+/*
+ * Read Transfer Active/ Write Transfer Active may be not
+ * de-asserted after end of transaction. Issue reset for DAT line.
+ */
+#define SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT (1<<1)
+/*
+ * Slow interrupt clearance at 400KHz may cause
+ * host controller driver interrupt handler to
+ * be called twice.
+ */
+#define SDHCI_QUIRK2_SLOW_INT_CLR (1<<2)
+/* Ignore CMD CRC errors for tuning commands */
+#define SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING (1<<3)
+
int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
@@ -147,6 +161,10 @@
u8 *adma_desc; /* ADMA descriptor table */
u8 *align_buffer; /* Bounce buffer */
+ unsigned int adma_desc_sz; /* ADMA descriptor table size */
+ unsigned int align_buf_sz; /* Bounce buffer size */
+ unsigned int adma_max_desc; /* Max ADMA descriptos (max sg segments) */
+
dma_addr_t adma_addr; /* Mapped ADMA descr. table */
dma_addr_t align_addr; /* Mapped bounce buffer */
diff --git a/include/linux/msm_ipa.h b/include/linux/msm_ipa.h
index 30bf4f2..b377a6c 100644
--- a/include/linux/msm_ipa.h
+++ b/include/linux/msm_ipa.h
@@ -49,7 +49,9 @@
#define IPA_IOCTL_V4_DEL_NAT 26
#define IPA_IOCTL_PULL_MSG 27
#define IPA_IOCTL_GET_NAT_OFFSET 28
-#define IPA_IOCTL_MAX 29
+#define IPA_IOCTL_RM_ADD_DEPENDENCY 29
+#define IPA_IOCTL_RM_DEL_DEPENDENCY 30
+#define IPA_IOCTL_MAX 31
/**
* max size of the header to be inserted
@@ -173,6 +175,35 @@
WLAN_STA_DISCONNECT,
};
+/**
+ * enum ipa_rm_resource_name - IPA RM clients identification names
+ *
+ * Add new mapping to ipa_rm_dep_prod_index() / ipa_rm_dep_cons_index()
+ * when adding new entry to this enum.
+ */
+enum ipa_rm_resource_name {
+ IPA_RM_RESOURCE_PROD = 0,
+ IPA_RM_RESOURCE_BRIDGE_PROD = IPA_RM_RESOURCE_PROD,
+ IPA_RM_RESOURCE_A2_PROD,
+ IPA_RM_RESOURCE_USB_PROD,
+ IPA_RM_RESOURCE_HSIC_PROD,
+ IPA_RM_RESOURCE_STD_ECM_PROD,
+ IPA_RM_RESOURCE_WWAN_0_PROD,
+ IPA_RM_RESOURCE_WWAN_1_PROD,
+ IPA_RM_RESOURCE_WWAN_2_PROD,
+ IPA_RM_RESOURCE_WWAN_3_PROD,
+ IPA_RM_RESOURCE_WWAN_4_PROD,
+ IPA_RM_RESOURCE_WWAN_5_PROD,
+ IPA_RM_RESOURCE_WWAN_6_PROD,
+ IPA_RM_RESOURCE_WWAN_7_PROD,
+ IPA_RM_RESOURCE_WLAN_PROD,
+ IPA_RM_RESOURCE_PROD_MAX,
+
+ IPA_RM_RESOURCE_A2_CONS = IPA_RM_RESOURCE_PROD_MAX,
+ IPA_RM_RESOURCE_USB_CONS,
+ IPA_RM_RESOURCE_HSIC_CONS,
+ IPA_RM_RESOURCE_MAX
+};
/**
* struct ipa_rule_attrib - attributes of a routing/filtering
@@ -682,6 +713,15 @@
uint8_t mac_addr[IPA_MAC_ADDR_SIZE];
};
+/**
+ * struct ipa_ioc_rm_dependency - parameters for add/delete dependency
+ * @resource_name: name of dependent resource
+ * @depends_on_name: name of its dependency
+ */
+struct ipa_ioc_rm_dependency {
+ enum ipa_rm_resource_name resource_name;
+ enum ipa_rm_resource_name depends_on_name;
+};
/**
@@ -768,6 +808,12 @@
#define IPA_IOC_PULL_MSG _IOWR(IPA_IOC_MAGIC, \
IPA_IOCTL_PULL_MSG, \
struct ipa_msg_meta *)
+#define IPA_IOC_RM_ADD_DEPENDENCY _IOWR(IPA_IOC_MAGIC, \
+ IPA_IOCTL_RM_ADD_DEPENDENCY, \
+ struct ipa_ioc_rm_dependency *)
+#define IPA_IOC_RM_DEL_DEPENDENCY _IOWR(IPA_IOC_MAGIC, \
+ IPA_IOCTL_RM_DEL_DEPENDENCY, \
+ struct ipa_ioc_rm_dependency *)
/*
* unique magic number of the Tethering bridge ioctls
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 0683296..6e4b7a6 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -554,14 +554,6 @@
* @NL80211_CMD_SET_NOACK_MAP: sets a bitmap for the individual TIDs whether
* No Acknowledgement Policy should be applied.
*
- * @NL80211_CMD_UPDATE_FT_IES: Pass down the most up-to-date Fast Transition
- * Information Element to the WLAN driver
- *
- * @NL80211_CMD_FT_EVENT: Send a Fast transition event from the WLAN driver
- * to the supplicant. This will carry the target AP's MAC address along
- * with the relevant Information Elements. This event to report received
- * FT IEs( MDIE, FTIE,RSN IE, TIE, RICIE).
- *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -703,9 +695,6 @@
NL80211_CMD_SET_NOACK_MAP,
- NL80211_CMD_UPDATE_FT_IES,
- NL80211_CMD_FT_EVENT,
-
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1281,10 +1270,6 @@
* @NL80211_ATTR_BG_SCAN_PERIOD: Background scan period in seconds
* or 0 to disable background scan.
*
- * @NL80211_ATTR_MDID: Mobility Domain Identifier
- *
- * @NL80211_ATTR_IE_RIC: Resource Information Container Information Element
- *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1536,9 +1521,6 @@
NL80211_ATTR_BG_SCAN_PERIOD,
- NL80211_ATTR_MDID,
- NL80211_ATTR_IE_RIC,
-
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
diff --git a/include/linux/uhid.h b/include/linux/uhid.h
index 16b786a..9c6974f 100644
--- a/include/linux/uhid.h
+++ b/include/linux/uhid.h
@@ -23,11 +23,82 @@
#include <linux/types.h>
enum uhid_event_type {
- UHID_DUMMY,
+ UHID_CREATE,
+ UHID_DESTROY,
+ UHID_START,
+ UHID_STOP,
+ UHID_OPEN,
+ UHID_CLOSE,
+ UHID_OUTPUT,
+ UHID_OUTPUT_EV,
+ UHID_INPUT,
+ UHID_FEATURE,
+ UHID_FEATURE_ANSWER,
+};
+
+struct uhid_create_req {
+ __u8 name[128];
+ __u8 phys[64];
+ __u8 uniq[64];
+ __u8 __user *rd_data;
+ __u16 rd_size;
+
+ __u16 bus;
+ __u32 vendor;
+ __u32 product;
+ __u32 version;
+ __u32 country;
+} __attribute__((__packed__));
+
+#define UHID_DATA_MAX 4096
+
+enum uhid_report_type {
+ UHID_FEATURE_REPORT,
+ UHID_OUTPUT_REPORT,
+ UHID_INPUT_REPORT,
+};
+
+struct uhid_input_req {
+ __u8 data[UHID_DATA_MAX];
+ __u16 size;
+} __attribute__((__packed__));
+
+struct uhid_output_req {
+ __u8 data[UHID_DATA_MAX];
+ __u16 size;
+ __u8 rtype;
+} __attribute__((__packed__));
+
+struct uhid_output_ev_req {
+ __u16 type;
+ __u16 code;
+ __s32 value;
+} __attribute__((__packed__));
+
+struct uhid_feature_req {
+ __u32 id;
+ __u8 rnum;
+ __u8 rtype;
+} __attribute__((__packed__));
+
+struct uhid_feature_answer_req {
+ __u32 id;
+ __u16 err;
+ __u16 size;
+ __u8 data[UHID_DATA_MAX];
};
struct uhid_event {
__u32 type;
+
+ union {
+ struct uhid_create_req create;
+ struct uhid_input_req input;
+ struct uhid_output_req output;
+ struct uhid_output_ev_req output_ev;
+ struct uhid_feature_req feature;
+ struct uhid_feature_answer_req feature_answer;
+ } u;
} __attribute__((__packed__));
#endif /* __UHID_H_ */
diff --git a/include/linux/usb/ehci_pdriver.h b/include/linux/usb/ehci_pdriver.h
index 4c1b7a0..1894f42 100644
--- a/include/linux/usb/ehci_pdriver.h
+++ b/include/linux/usb/ehci_pdriver.h
@@ -41,7 +41,6 @@
unsigned big_endian_mmio:1;
unsigned port_power_on:1;
unsigned port_power_off:1;
- unsigned pool_64_bit_align:1;
};
#endif /* __USB_CORE_EHCI_PDRIVER_H */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index e249953..b65a6d2 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -407,6 +407,7 @@
/*standalone latency is required when HSCI is active*/
u32 standalone_latency;
+ bool pool_64_bit_align;
};
struct msm_usb_host_platform_data {
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index fae1efa..c53d604 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -17,20 +17,6 @@
MSM_VIDC_MAX_DEVICES,
};
-struct msm_vidc_iommu_info {
- u32 addr_range[2];
- char name[64];
- char ctx[64];
- int domain;
- int partition;
-};
-
-enum msm_vidc_io_maps {
- CP_MAP,
- NS_MAP,
- MAX_MAP
-};
-
void *msm_vidc_open(int core_id, int session_type);
int msm_vidc_close(void *instance);
int msm_vidc_querycap(void *instance, struct v4l2_capability *cap);
@@ -50,8 +36,8 @@
int msm_vidc_encoder_cmd(void *instance, struct v4l2_encoder_cmd *enc);
int msm_vidc_poll(void *instance, struct file *filp,
struct poll_table_struct *pt);
-int msm_vidc_get_iommu_maps(void *instance,
- struct msm_vidc_iommu_info maps[MAX_MAP]);
+int msm_vidc_get_iommu_domain_partition(void *instance, u32 flags,
+ enum v4l2_buf_type, int *domain, int *partition);
int msm_vidc_subscribe_event(void *instance,
struct v4l2_event_subscription *sub);
int msm_vidc_unsubscribe_event(void *instance,
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index 6bac1d6..56c257d 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -89,10 +89,9 @@
struct ion_handle *dest_ion_handle;
};
-struct msm_ver_num_info {
- uint32_t main;
- uint32_t minor;
- uint32_t rev;
+struct cpp_hw_info {
+ uint32_t cpp_hw_version;
+ uint32_t cpp_hw_caps;
};
#define VIDIOC_MSM_CPP_CFG \
@@ -107,6 +106,9 @@
#define VIDIOC_MSM_CPP_LOAD_FIRMWARE \
_IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct msm_camera_v4l2_ioctl_t)
+#define VIDIOC_MSM_CPP_GET_HW_INFO \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct msm_camera_v4l2_ioctl_t)
+
#define V4L2_EVENT_CPP_FRAME_DONE (V4L2_EVENT_PRIVATE_START + 0)
struct msm_camera_v4l2_ioctl_t {
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 6666c69..3a7edf3 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1320,21 +1320,6 @@
};
/**
- * struct cfg80211_update_ft_ies_params - FT IE Information
- *
- * This structure provides information needed to update the fast transition IE
- *
- * @md: The Mobility Domain ID, 2 Octet value
- * @ie: Fast Transition IEs
- * @ie_len: Length of ft_ie in octets
- */
-struct cfg80211_update_ft_ies_params {
- u16 md;
- u8 *ie;
- size_t ie_len;
-};
-
-/**
* struct cfg80211_ops - backend description for wireless configuration
*
* This struct is registered by fullmac card drivers and/or wireless stacks
@@ -1714,8 +1699,6 @@
u16 noack_map);
struct ieee80211_channel *(*get_channel)(struct wiphy *wiphy);
- int (*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev,
- struct cfg80211_update_ft_ies_params *ftie);
};
/*
@@ -3386,32 +3369,6 @@
*/
u16 cfg80211_calculate_bitrate(struct rate_info *rate);
-/**
- * struct cfg80211_ft_event - FT Information Elements
- * @dev: network device
- * @ies: FT IEs
- * @ies_len: length of the FT IE in bytes
- * @target_ap: target AP's MAC address
- * @ric_ies: RIC IE
- * @ric_ies_len: length of the RIC IE in bytes
- */
-struct cfg80211_ft_event_params {
- u8 *ies;
- size_t ies_len;
- u8 target_ap[ETH_ALEN];
- u8 *ric_ies;
- size_t ric_ies_len;
-};
-
-/**
- * cfg80211_ft_event - notify userspace about FT IE and RIC IE
- * @dev: network device
- * @cfg80211_ft_event_params: IE information
- */
-int cfg80211_ft_event(struct net_device *dev,
- struct cfg80211_ft_event_params ft_event);
-
-
/* Logging, debugging and troubleshooting/diagnostic helpers. */
/* wiphy_printk helpers, similar to dev_printk */
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index dd99041..f5a7ac3 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -954,16 +954,3 @@
return nl80211_unexpected_4addr_frame(dev, addr, gfp);
}
EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
-
-int cfg80211_ft_event(struct net_device *dev,
- struct cfg80211_ft_event_params ft_event)
-{
- int err = 0;
- struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
- struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
- nl80211_ft_event(rdev, dev, ft_event);
-
- return err;
-}
-EXPORT_SYMBOL(cfg80211_ft_event);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 1ccc69e..68a6b17 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -206,9 +206,6 @@
[NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 },
[NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 },
[NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
- [NL80211_ATTR_MDID] = { .type = NLA_U16 },
- [NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
- .len = IEEE80211_MAX_DATA_LEN },
};
/* policy for the key attributes */
@@ -6311,26 +6308,6 @@
return 0;
}
-static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info)
-{
- struct cfg80211_registered_device *rdev = info->user_ptr[0];
- struct cfg80211_update_ft_ies_params ft_params;
- struct net_device *dev = info->user_ptr[1];
-
- if (!info->attrs[NL80211_ATTR_MDID])
- return -EINVAL;
-
- ft_params.md = nla_get_u16(info->attrs[NL80211_ATTR_MDID]);
-
- if (!info->attrs[NL80211_ATTR_IE])
- return -EINVAL;
-
- ft_params.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
- ft_params.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
-
- return rdev->ops->update_ft_ies(&rdev->wiphy, dev, &ft_params);
-}
-
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -6919,14 +6896,6 @@
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
},
- {
- .cmd = NL80211_CMD_UPDATE_FT_IES,
- .doit = nl80211_update_ft_ies,
- .policy = nl80211_policy,
- .flags = GENL_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
- },
};
@@ -8164,47 +8133,6 @@
.notifier_call = nl80211_netlink_notify,
};
-void nl80211_ft_event(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, struct cfg80211_ft_event_params ft_event)
-{
- struct sk_buff *msg;
- void *hdr;
-
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
- if (!msg)
- return;
-
- hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FT_EVENT);
- if (!hdr) {
- nlmsg_free(msg);
- return;
- }
-
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
- if (ft_event.target_ap)
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event.target_ap);
- if (ft_event.ies)
- NLA_PUT(msg, NL80211_ATTR_IE, ft_event.ies_len, ft_event.ies);
- if (ft_event.ric_ies)
- NLA_PUT(msg, NL80211_ATTR_IE_RIC, ft_event.ric_ies_len,
- ft_event.ric_ies);
-
- if (genlmsg_end(msg, hdr) < 0) {
- nlmsg_free(msg);
- return;
- }
-
- genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
- nl80211_mlme_mcgrp.id, GFP_KERNEL);
- return;
-
- nla_put_failure:
- genlmsg_cancel(msg, hdr);
- nlmsg_free(msg);
-}
-
-
/* initialisation/exit functions */
int nl80211_init(void)
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index ffd4c8a..4ffe50d 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -123,8 +123,4 @@
bool nl80211_unexpected_4addr_frame(struct net_device *dev,
const u8 *addr, gfp_t gfp);
-void nl80211_ft_event(struct cfg80211_registered_device *rdev,
- struct net_device *netdev,
- struct cfg80211_ft_event_params ft_event);
-
#endif /* __NET_WIRELESS_NL80211_H */
diff --git a/samples/uhid/Makefile b/samples/uhid/Makefile
new file mode 100644
index 0000000..c95a696
--- /dev/null
+++ b/samples/uhid/Makefile
@@ -0,0 +1,10 @@
+# kbuild trick to avoid linker error. Can be omitted if a module is built.
+obj- := dummy.o
+
+# List of programs to build
+hostprogs-y := uhid-example
+
+# Tell kbuild to always build the programs
+always := $(hostprogs-y)
+
+HOSTCFLAGS_uhid-example.o += -I$(objtree)/usr/include
diff --git a/samples/uhid/uhid-example.c b/samples/uhid/uhid-example.c
new file mode 100644
index 0000000..03ce3c0
--- /dev/null
+++ b/samples/uhid/uhid-example.c
@@ -0,0 +1,381 @@
+/*
+ * UHID Example
+ *
+ * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
+ *
+ * The code may be used by anyone for any purpose,
+ * and can serve as a starting point for developing
+ * applications using uhid.
+ */
+
+/* UHID Example
+ * This example emulates a basic 3 buttons mouse with wheel over UHID. Run this
+ * program as root and then use the following keys to control the mouse:
+ * q: Quit the application
+ * 1: Toggle left button (down, up, ...)
+ * 2: Toggle right button
+ * 3: Toggle middle button
+ * a: Move mouse left
+ * d: Move mouse right
+ * w: Move mouse up
+ * s: Move mouse down
+ * r: Move wheel up
+ * f: Move wheel down
+ *
+ * If uhid is not available as /dev/uhid, then you can pass a different path as
+ * first argument.
+ * If <linux/uhid.h> is not installed in /usr, then compile this with:
+ * gcc -o ./uhid_test -Wall -I./include ./samples/uhid/uhid-example.c
+ * And ignore the warning about kernel headers. However, it is recommended to
+ * use the installed uhid.h if available.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <linux/uhid.h>
+
+/* HID Report Desciptor
+ * We emulate a basic 3 button mouse with wheel. This is the report-descriptor
+ * as the kernel will parse it:
+ *
+ * INPUT[INPUT]
+ * Field(0)
+ * Physical(GenericDesktop.Pointer)
+ * Application(GenericDesktop.Mouse)
+ * Usage(3)
+ * Button.0001
+ * Button.0002
+ * Button.0003
+ * Logical Minimum(0)
+ * Logical Maximum(1)
+ * Report Size(1)
+ * Report Count(3)
+ * Report Offset(0)
+ * Flags( Variable Absolute )
+ * Field(1)
+ * Physical(GenericDesktop.Pointer)
+ * Application(GenericDesktop.Mouse)
+ * Usage(3)
+ * GenericDesktop.X
+ * GenericDesktop.Y
+ * GenericDesktop.Wheel
+ * Logical Minimum(-128)
+ * Logical Maximum(127)
+ * Report Size(8)
+ * Report Count(3)
+ * Report Offset(8)
+ * Flags( Variable Relative )
+ *
+ * This is the mapping that we expect:
+ * Button.0001 ---> Key.LeftBtn
+ * Button.0002 ---> Key.RightBtn
+ * Button.0003 ---> Key.MiddleBtn
+ * GenericDesktop.X ---> Relative.X
+ * GenericDesktop.Y ---> Relative.Y
+ * GenericDesktop.Wheel ---> Relative.Wheel
+ *
+ * This information can be verified by reading /sys/kernel/debug/hid/<dev>/rdesc
+ * This file should print the same information as showed above.
+ */
+
+static unsigned char rdesc[] = {
+ 0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01,
+ 0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
+ 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01,
+ 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01,
+ 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x38,
+ 0x15, 0x80, 0x25, 0x7f, 0x75, 0x08, 0x95, 0x03,
+ 0x81, 0x06, 0xc0, 0xc0,
+};
+
+static int uhid_write(int fd, const struct uhid_event *ev)
+{
+ ssize_t ret;
+
+ ret = write(fd, ev, sizeof(*ev));
+ if (ret < 0) {
+ fprintf(stderr, "Cannot write to uhid: %m\n");
+ return -errno;
+ } else if (ret != sizeof(*ev)) {
+ fprintf(stderr, "Wrong size written to uhid: %ld != %lu\n",
+ ret, sizeof(ev));
+ return -EFAULT;
+ } else {
+ return 0;
+ }
+}
+
+static int create(int fd)
+{
+ struct uhid_event ev;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.type = UHID_CREATE;
+ strcpy((char*)ev.u.create.name, "test-uhid-device");
+ ev.u.create.rd_data = rdesc;
+ ev.u.create.rd_size = sizeof(rdesc);
+ ev.u.create.bus = BUS_USB;
+ ev.u.create.vendor = 0x15d9;
+ ev.u.create.product = 0x0a37;
+ ev.u.create.version = 0;
+ ev.u.create.country = 0;
+
+ return uhid_write(fd, &ev);
+}
+
+static void destroy(int fd)
+{
+ struct uhid_event ev;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.type = UHID_DESTROY;
+
+ uhid_write(fd, &ev);
+}
+
+static int event(int fd)
+{
+ struct uhid_event ev;
+ ssize_t ret;
+
+ memset(&ev, 0, sizeof(ev));
+ ret = read(fd, &ev, sizeof(ev));
+ if (ret == 0) {
+ fprintf(stderr, "Read HUP on uhid-cdev\n");
+ return -EFAULT;
+ } else if (ret < 0) {
+ fprintf(stderr, "Cannot read uhid-cdev: %m\n");
+ return -errno;
+ } else if (ret != sizeof(ev)) {
+ fprintf(stderr, "Invalid size read from uhid-dev: %ld != %lu\n",
+ ret, sizeof(ev));
+ return -EFAULT;
+ }
+
+ switch (ev.type) {
+ case UHID_START:
+ fprintf(stderr, "UHID_START from uhid-dev\n");
+ break;
+ case UHID_STOP:
+ fprintf(stderr, "UHID_STOP from uhid-dev\n");
+ break;
+ case UHID_OPEN:
+ fprintf(stderr, "UHID_OPEN from uhid-dev\n");
+ break;
+ case UHID_CLOSE:
+ fprintf(stderr, "UHID_CLOSE from uhid-dev\n");
+ break;
+ case UHID_OUTPUT:
+ fprintf(stderr, "UHID_OUTPUT from uhid-dev\n");
+ break;
+ case UHID_OUTPUT_EV:
+ fprintf(stderr, "UHID_OUTPUT_EV from uhid-dev\n");
+ break;
+ default:
+ fprintf(stderr, "Invalid event from uhid-dev: %u\n", ev.type);
+ }
+
+ return 0;
+}
+
+static bool btn1_down;
+static bool btn2_down;
+static bool btn3_down;
+static signed char abs_hor;
+static signed char abs_ver;
+static signed char wheel;
+
+static int send_event(int fd)
+{
+ struct uhid_event ev;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.type = UHID_INPUT;
+ ev.u.input.size = 4;
+
+ if (btn1_down)
+ ev.u.input.data[0] |= 0x1;
+ if (btn2_down)
+ ev.u.input.data[0] |= 0x2;
+ if (btn3_down)
+ ev.u.input.data[0] |= 0x4;
+
+ ev.u.input.data[1] = abs_hor;
+ ev.u.input.data[2] = abs_ver;
+ ev.u.input.data[3] = wheel;
+
+ return uhid_write(fd, &ev);
+}
+
+static int keyboard(int fd)
+{
+ char buf[128];
+ ssize_t ret, i;
+
+ ret = read(STDIN_FILENO, buf, sizeof(buf));
+ if (ret == 0) {
+ fprintf(stderr, "Read HUP on stdin\n");
+ return -EFAULT;
+ } else if (ret < 0) {
+ fprintf(stderr, "Cannot read stdin: %m\n");
+ return -errno;
+ }
+
+ for (i = 0; i < ret; ++i) {
+ switch (buf[i]) {
+ case '1':
+ btn1_down = !btn1_down;
+ ret = send_event(fd);
+ if (ret)
+ return ret;
+ break;
+ case '2':
+ btn2_down = !btn2_down;
+ ret = send_event(fd);
+ if (ret)
+ return ret;
+ break;
+ case '3':
+ btn3_down = !btn3_down;
+ ret = send_event(fd);
+ if (ret)
+ return ret;
+ break;
+ case 'a':
+ abs_hor = -20;
+ ret = send_event(fd);
+ abs_hor = 0;
+ if (ret)
+ return ret;
+ break;
+ case 'd':
+ abs_hor = 20;
+ ret = send_event(fd);
+ abs_hor = 0;
+ if (ret)
+ return ret;
+ break;
+ case 'w':
+ abs_ver = -20;
+ ret = send_event(fd);
+ abs_ver = 0;
+ if (ret)
+ return ret;
+ break;
+ case 's':
+ abs_ver = 20;
+ ret = send_event(fd);
+ abs_ver = 0;
+ if (ret)
+ return ret;
+ break;
+ case 'r':
+ wheel = 1;
+ ret = send_event(fd);
+ wheel = 0;
+ if (ret)
+ return ret;
+ break;
+ case 'f':
+ wheel = -1;
+ ret = send_event(fd);
+ wheel = 0;
+ if (ret)
+ return ret;
+ break;
+ case 'q':
+ return -ECANCELED;
+ default:
+ fprintf(stderr, "Invalid input: %c\n", buf[i]);
+ }
+ }
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int fd;
+ const char *path = "/dev/uhid";
+ struct pollfd pfds[2];
+ int ret;
+ struct termios state;
+
+ ret = tcgetattr(STDIN_FILENO, &state);
+ if (ret) {
+ fprintf(stderr, "Cannot get tty state\n");
+ } else {
+ state.c_lflag &= ~ICANON;
+ state.c_cc[VMIN] = 1;
+ ret = tcsetattr(STDIN_FILENO, TCSANOW, &state);
+ if (ret)
+ fprintf(stderr, "Cannot set tty state\n");
+ }
+
+ if (argc >= 2) {
+ if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
+ fprintf(stderr, "Usage: %s [%s]\n", argv[0], path);
+ return EXIT_SUCCESS;
+ } else {
+ path = argv[1];
+ }
+ }
+
+ fprintf(stderr, "Open uhid-cdev %s\n", path);
+ fd = open(path, O_RDWR | O_CLOEXEC);
+ if (fd < 0) {
+ fprintf(stderr, "Cannot open uhid-cdev %s: %m\n", path);
+ return EXIT_FAILURE;
+ }
+
+ fprintf(stderr, "Create uhid device\n");
+ ret = create(fd);
+ if (ret) {
+ close(fd);
+ return EXIT_FAILURE;
+ }
+
+ pfds[0].fd = STDIN_FILENO;
+ pfds[0].events = POLLIN;
+ pfds[1].fd = fd;
+ pfds[1].events = POLLIN;
+
+ fprintf(stderr, "Press 'q' to quit...\n");
+ while (1) {
+ ret = poll(pfds, 2, -1);
+ if (ret < 0) {
+ fprintf(stderr, "Cannot poll for fds: %m\n");
+ break;
+ }
+ if (pfds[0].revents & POLLHUP) {
+ fprintf(stderr, "Received HUP on stdin\n");
+ break;
+ }
+ if (pfds[1].revents & POLLHUP) {
+ fprintf(stderr, "Received HUP on uhid-cdev\n");
+ break;
+ }
+
+ if (pfds[0].revents & POLLIN) {
+ ret = keyboard(fd);
+ if (ret)
+ break;
+ }
+ if (pfds[1].revents & POLLIN) {
+ ret = event(fd);
+ if (ret)
+ break;
+ }
+ }
+
+ fprintf(stderr, "Destroy uhid device\n");
+ destroy(fd);
+ return EXIT_SUCCESS;
+}
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index b3d4901..af268bd 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -1807,28 +1807,61 @@
struct snd_soc_codec *codec = w->codec;
u16 adc_reg;
u8 init_bit_shift;
+ struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
pr_debug("%s %d\n", __func__, event);
- if (w->reg == TAIKO_A_TX_1_2_EN)
- adc_reg = TAIKO_A_TX_1_2_TEST_CTL;
- else if (w->reg == TAIKO_A_TX_3_4_EN)
- adc_reg = TAIKO_A_TX_3_4_TEST_CTL;
- else if (w->reg == TAIKO_A_TX_5_6_EN)
- adc_reg = TAIKO_A_TX_5_6_TEST_CTL;
- else {
- pr_err("%s: Error, invalid adc register\n", __func__);
- return -EINVAL;
- }
+ if (TAIKO_IS_1_0(core->version)) {
+ if (w->reg == TAIKO_A_TX_1_2_EN) {
+ adc_reg = TAIKO_A_TX_1_2_TEST_CTL;
+ } else if (w->reg == TAIKO_A_TX_3_4_EN) {
+ adc_reg = TAIKO_A_TX_3_4_TEST_CTL;
+ } else if (w->reg == TAIKO_A_TX_5_6_EN) {
+ adc_reg = TAIKO_A_TX_5_6_TEST_CTL;
+ } else {
+ pr_err("%s: Error, invalid adc register\n", __func__);
+ return -EINVAL;
+ }
- if (w->shift == 3)
- init_bit_shift = 6;
- else if (w->shift == 7)
- init_bit_shift = 7;
- else {
- pr_err("%s: Error, invalid init bit postion adc register\n",
- __func__);
- return -EINVAL;
+ if (w->shift == 3) {
+ init_bit_shift = 6;
+ } else if (w->shift == 7) {
+ init_bit_shift = 7;
+ } else {
+ pr_err("%s: Error, invalid init bit postion adc register\n",
+ __func__);
+ return -EINVAL;
+ }
+ } else {
+ switch (w->reg) {
+ case TAIKO_A_CDC_TX_1_GAIN:
+ adc_reg = TAIKO_A_TX_1_2_TEST_CTL;
+ init_bit_shift = 7;
+ break;
+ case TAIKO_A_CDC_TX_2_GAIN:
+ adc_reg = TAIKO_A_TX_1_2_TEST_CTL;
+ init_bit_shift = 6;
+ break;
+ case TAIKO_A_CDC_TX_3_GAIN:
+ adc_reg = TAIKO_A_TX_3_4_TEST_CTL;
+ init_bit_shift = 7;
+ break;
+ case TAIKO_A_CDC_TX_4_GAIN:
+ adc_reg = TAIKO_A_TX_3_4_TEST_CTL;
+ init_bit_shift = 6;
+ break;
+ case TAIKO_A_CDC_TX_5_GAIN:
+ adc_reg = TAIKO_A_TX_5_6_TEST_CTL;
+ init_bit_shift = 7;
+ break;
+ case TAIKO_A_CDC_TX_6_GAIN:
+ adc_reg = TAIKO_A_TX_5_6_TEST_CTL;
+ init_bit_shift = 6;
+ break;
+ default:
+ pr_err("%s: Error, invalid adc register\n", __func__);
+ return -EINVAL;
+ }
}
switch (event) {
@@ -1838,9 +1871,7 @@
1 << init_bit_shift);
break;
case SND_SOC_DAPM_POST_PMU:
-
snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
-
break;
case SND_SOC_DAPM_POST_PMD:
taiko_codec_enable_adc_block(codec, 0);
@@ -2151,14 +2182,14 @@
e_post_on = WCD9XXX_EVENT_POST_MICBIAS_2_ON;
e_post_off = WCD9XXX_EVENT_POST_MICBIAS_2_OFF;
} else if (strnstr(w->name, "MIC BIAS3", sizeof("MIC BIAS3"))) {
- micb_ctl_reg = TAIKO_A_MICB_2_CTL;
+ micb_ctl_reg = TAIKO_A_MICB_3_CTL;
micb_int_reg = TAIKO_A_MICB_3_INT_RBIAS;
cfilt_sel_val = taiko->resmgr.pdata->micbias.bias3_cfilt_sel;
e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_3_ON;
e_post_on = WCD9XXX_EVENT_POST_MICBIAS_3_ON;
e_post_off = WCD9XXX_EVENT_POST_MICBIAS_3_OFF;
} else if (strnstr(w->name, "MIC BIAS4", sizeof("MIC BIAS4"))) {
- micb_ctl_reg = TAIKO_A_MICB_2_CTL;
+ micb_ctl_reg = TAIKO_A_MICB_4_CTL;
micb_int_reg = taiko->resmgr.reg_addr->micb_4_int_rbias;
cfilt_sel_val = taiko->resmgr.pdata->micbias.bias4_cfilt_sel;
e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_4_ON;
@@ -2184,14 +2215,12 @@
else if (strnstr(w->name, internal3_text, 30))
snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
- if (micb_ctl_reg == TAIKO_A_MICB_2_CTL) {
- WCD9XXX_BCL_LOCK(&taiko->resmgr);
+ if (micb_ctl_reg == TAIKO_A_MICB_2_CTL)
wcd9xxx_resmgr_add_cond_update_bits(&taiko->resmgr,
WCD9XXX_COND_HPH_MIC,
micb_ctl_reg, w->shift,
false);
- WCD9XXX_BCL_UNLOCK(&taiko->resmgr);
- } else
+ else
snd_soc_update_bits(codec, micb_ctl_reg, 1 << w->shift,
1 << w->shift);
break;
@@ -2201,13 +2230,11 @@
wcd9xxx_resmgr_notifier_call(&taiko->resmgr, e_post_on);
break;
case SND_SOC_DAPM_POST_PMD:
- if (micb_ctl_reg == TAIKO_A_MICB_2_CTL) {
- WCD9XXX_BCL_LOCK(&taiko->resmgr);
+ if (micb_ctl_reg == TAIKO_A_MICB_2_CTL)
wcd9xxx_resmgr_rm_cond_update_bits(&taiko->resmgr,
WCD9XXX_COND_HPH_MIC,
micb_ctl_reg, 7, false);
- WCD9XXX_BCL_UNLOCK(&taiko->resmgr);
- } else
+ else
snd_soc_update_bits(codec, micb_ctl_reg, 1 << w->shift,
0);
@@ -4299,27 +4326,14 @@
taiko_codec_enable_micbias,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_ADC_E("ADC1", NULL, TAIKO_A_TX_1_2_EN, 7, 0,
- taiko_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_INPUT("AMIC3"),
- SND_SOC_DAPM_ADC_E("ADC3", NULL, TAIKO_A_TX_3_4_EN, 7, 0,
- taiko_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_INPUT("AMIC4"),
- SND_SOC_DAPM_ADC_E("ADC4", NULL, TAIKO_A_TX_3_4_EN, 3, 0,
- taiko_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_INPUT("AMIC5"),
- SND_SOC_DAPM_ADC_E("ADC5", NULL, TAIKO_A_TX_5_6_EN, 7, 0,
- taiko_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_INPUT("AMIC6"),
- SND_SOC_DAPM_ADC_E("ADC6", NULL, TAIKO_A_TX_5_6_EN, 3, 0,
- taiko_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_MUX_E("DEC1 MUX", TAIKO_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
&dec1_mux, taiko_codec_enable_dec,
@@ -4414,10 +4428,6 @@
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_ADC_E("ADC2", NULL, TAIKO_A_TX_1_2_EN, 3, 0,
- taiko_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
AIF1_CAP, 0, taiko_codec_enable_slimtx,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -5067,6 +5077,56 @@
return buck_volt;
}
+static const struct snd_soc_dapm_widget taiko_1_dapm_widgets[] = {
+ SND_SOC_DAPM_ADC_E("ADC1", NULL, TAIKO_A_TX_1_2_EN, 7, 0,
+ taiko_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC2", NULL, TAIKO_A_TX_1_2_EN, 3, 0,
+ taiko_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC3", NULL, TAIKO_A_TX_3_4_EN, 7, 0,
+ taiko_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC4", NULL, TAIKO_A_TX_3_4_EN, 3, 0,
+ taiko_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC5", NULL, TAIKO_A_TX_5_6_EN, 7, 0,
+ taiko_codec_enable_adc,
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_ADC_E("ADC6", NULL, TAIKO_A_TX_5_6_EN, 3, 0,
+ taiko_codec_enable_adc,
+ SND_SOC_DAPM_POST_PMU),
+};
+
+static const struct snd_soc_dapm_widget taiko_2_dapm_widgets[] = {
+ SND_SOC_DAPM_ADC_E("ADC1", NULL, TAIKO_A_CDC_TX_1_GAIN, 7, 0,
+ taiko_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC2", NULL, TAIKO_A_CDC_TX_2_GAIN, 7, 0,
+ taiko_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC3", NULL, TAIKO_A_CDC_TX_3_GAIN, 7, 0,
+ taiko_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC4", NULL, TAIKO_A_CDC_TX_4_GAIN, 7, 0,
+ taiko_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC5", NULL, TAIKO_A_CDC_TX_5_GAIN, 7, 0,
+ taiko_codec_enable_adc,
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_ADC_E("ADC6", NULL, TAIKO_A_CDC_TX_6_GAIN, 7, 0,
+ taiko_codec_enable_adc,
+ SND_SOC_DAPM_POST_PMU),
+};
+
static int taiko_codec_probe(struct snd_soc_codec *codec)
{
struct wcd9xxx *control;
@@ -5113,7 +5173,7 @@
}
taiko->clsh_d.buck_mv = taiko_codec_get_buck_mv(codec);
- wcd9xxx_clsh_init(&taiko->clsh_d);
+ wcd9xxx_clsh_init(&taiko->clsh_d, &taiko->resmgr);
/* init and start mbhc */
ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec);
@@ -5179,6 +5239,13 @@
}
}
+ if (TAIKO_IS_1_0(control->version))
+ snd_soc_dapm_new_controls(dapm, taiko_1_dapm_widgets,
+ ARRAY_SIZE(taiko_1_dapm_widgets));
+ else
+ snd_soc_dapm_new_controls(dapm, taiko_2_dapm_widgets,
+ ARRAY_SIZE(taiko_2_dapm_widgets));
+
control->num_rx_port = TAIKO_RX_MAX;
control->rx_chs = ptr;
memcpy(control->rx_chs, taiko_rx_chs, sizeof(taiko_rx_chs));
diff --git a/sound/soc/codecs/wcd9xxx-common.c b/sound/soc/codecs/wcd9xxx-common.c
index dbf2e39..f1b6203 100644
--- a/sound/soc/codecs/wcd9xxx-common.c
+++ b/sound/soc/codecs/wcd9xxx-common.c
@@ -165,33 +165,38 @@
}
}
-static inline void wcd9xxx_clsh_computation_request(
- struct snd_soc_codec *codec, int compute_pa, bool on)
+static void wcd9xxx_clsh_comp_req(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ int compute_pa, bool on)
{
- u8 reg_val, reg_mask;
+ u8 shift;
- switch (compute_pa) {
- case CLSH_COMPUTE_EAR:
- reg_mask = 0x10;
- reg_val = (on ? 0x10 : 0x00);
- break;
- case CLSH_COMPUTE_HPH_L:
- reg_mask = 0x08;
- reg_val = (on ? 0x08 : 0x00);
- break;
- case CLSH_COMPUTE_HPH_R:
- reg_mask = 0x04;
- reg_val = (on ? 0x04 : 0x00);
- break;
- default:
- dev_dbg(codec->dev, "%s: class h computation PA request incorrect\n",
- __func__);
- return;
+ if (compute_pa == CLSH_COMPUTE_EAR) {
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL, 0x10,
+ (on ? 0x10 : 0));
+ } else {
+ if (compute_pa == CLSH_COMPUTE_HPH_L) {
+ shift = 3;
+ } else if (compute_pa == CLSH_COMPUTE_HPH_R) {
+ shift = 2;
+ } else {
+ dev_dbg(codec->dev,
+ "%s: classh computation request is incorrect\n",
+ __func__);
+ return;
+ }
+
+ if (on)
+ wcd9xxx_resmgr_add_cond_update_bits(clsh_d->resmgr,
+ WCD9XXX_COND_HPH,
+ WCD9XXX_A_CDC_CLSH_B1_CTL,
+ shift, false);
+ else
+ wcd9xxx_resmgr_rm_cond_update_bits(clsh_d->resmgr,
+ WCD9XXX_COND_HPH,
+ WCD9XXX_A_CDC_CLSH_B1_CTL,
+ shift, false);
}
-
- snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
- reg_mask, reg_val);
-
}
static void wcd9xxx_enable_buck_mode(struct snd_soc_codec *codec,
@@ -355,12 +360,12 @@
if (req_state == WCD9XXX_CLSH_STATE_EAR) {
wcd9xxx_clsh_turnoff_postpa(codec);
} else if (req_state == WCD9XXX_CLSH_STATE_HPHL) {
- wcd9xxx_clsh_computation_request(codec,
- CLSH_COMPUTE_HPH_L, false);
+ wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L,
+ false);
wcd9xxx_clsh_turnoff_postpa(codec);
} else if (req_state == WCD9XXX_CLSH_STATE_HPHR) {
- wcd9xxx_clsh_computation_request(codec,
- CLSH_COMPUTE_HPH_R, false);
+ wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R,
+ false);
wcd9xxx_clsh_turnoff_postpa(codec);
} else if (req_state == WCD9XXX_CLSH_STATE_LO) {
wcd9xxx_enable_ncp(codec, false);
@@ -380,8 +385,7 @@
wcd9xxx_enable_clsh_block(codec, true);
wcd9xxx_chargepump_request(codec, true);
wcd9xxx_enable_anc_delay(codec, true);
- wcd9xxx_clsh_computation_request(codec,
- CLSH_COMPUTE_EAR, true);
+ wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_EAR, true);
wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
@@ -402,16 +406,15 @@
wcd9xxx_enable_clsh_block(codec, true);
wcd9xxx_chargepump_request(codec, true);
wcd9xxx_enable_anc_delay(codec, true);
- wcd9xxx_clsh_computation_request(codec,
- CLSH_COMPUTE_HPH_L, true);
+ wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, true);
wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
dev_dbg(codec->dev, "%s: Done\n", __func__);
} else {
if (req_state == WCD9XXX_CLSH_STATE_HPHR) {
- wcd9xxx_clsh_computation_request(codec,
- CLSH_COMPUTE_HPH_R, false);
+ wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R,
+ false);
} else {
dev_dbg(codec->dev, "%s: stub fallback to hph_l\n",
__func__);
@@ -431,16 +434,15 @@
wcd9xxx_enable_clsh_block(codec, true);
wcd9xxx_chargepump_request(codec, true);
wcd9xxx_enable_anc_delay(codec, true);
- wcd9xxx_clsh_computation_request(codec,
- CLSH_COMPUTE_HPH_R, true);
+ wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, true);
wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
dev_dbg(codec->dev, "%s: Done\n", __func__);
} else {
if (req_state == WCD9XXX_CLSH_STATE_HPHL) {
- wcd9xxx_clsh_computation_request(codec,
- CLSH_COMPUTE_HPH_L, false);
+ wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L,
+ false);
} else {
dev_dbg(codec->dev, "%s: stub fallback to hph_r\n",
__func__);
@@ -453,10 +455,8 @@
u8 req_state, bool is_enable)
{
if (is_enable) {
- wcd9xxx_clsh_computation_request(codec,
- CLSH_COMPUTE_HPH_L, true);
- wcd9xxx_clsh_computation_request(codec,
- CLSH_COMPUTE_HPH_R, true);
+ wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, true);
+ wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, true);
} else {
dev_dbg(codec->dev, "%s: stub fallback to hph_st\n", __func__);
}
@@ -566,10 +566,12 @@
}
EXPORT_SYMBOL_GPL(wcd9xxx_clsh_fsm);
-void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh)
+void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh,
+ struct wcd9xxx_resmgr *resmgr)
{
int i;
clsh->state = WCD9XXX_CLSH_STATE_IDLE;
+ clsh->resmgr = resmgr;
for (i = 0; i < NUM_CLSH_STATES; i++)
clsh_state_fp[i] = wcd9xxx_clsh_state_err;
diff --git a/sound/soc/codecs/wcd9xxx-common.h b/sound/soc/codecs/wcd9xxx-common.h
index 743ab0c..dc00ec6 100644
--- a/sound/soc/codecs/wcd9xxx-common.h
+++ b/sound/soc/codecs/wcd9xxx-common.h
@@ -14,6 +14,8 @@
#define WCD9XXX_CODEC_COMMON
+#include "wcd9xxx-resmgr.h"
+
#define WCD9XXX_CLSH_REQ_ENABLE true
#define WCD9XXX_CLSH_REQ_DISABLE false
@@ -50,6 +52,7 @@
struct wcd9xxx_clsh_cdc_data {
u8 state;
int buck_mv;
+ struct wcd9xxx_resmgr *resmgr;
};
@@ -63,6 +66,7 @@
struct wcd9xxx_clsh_cdc_data *cdc_clsh_d,
u8 req_state, bool req_type, u8 clsh_event);
-extern void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh);
+extern void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh,
+ struct wcd9xxx_resmgr *resmgr);
#endif
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index b3549cc..88f0567 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -85,6 +85,8 @@
#define WCD9XXX_HPHL_STATUS_READY_WAIT_US 1000
#define WCD9XXX_MUX_SWITCH_READY_WAIT_US 100
#define WCD9XXX_MEAS_DELTA_MAX_MV 50
+#define WCD9XXX_MEAS_INVALD_RANGE_LOW_MV 20
+#define WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV 80
#define WCD9XXX_GM_SWAP_THRES_MIN_MV 150
#define WCD9XXX_GM_SWAP_THRES_MAX_MV 500
@@ -377,10 +379,14 @@
static void wcd9xxx_jack_report(struct wcd9xxx_mbhc *mbhc,
struct snd_soc_jack *jack, int status, int mask)
{
- if (jack == &mbhc->headset_jack)
+ if (jack == &mbhc->headset_jack) {
wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
WCD9XXX_COND_HPH_MIC,
status & SND_JACK_MICROPHONE);
+ wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
+ WCD9XXX_COND_HPH,
+ status & SND_JACK_HEADPHONE);
+ }
snd_soc_jack_report_no_dapm(jack, status, mask);
}
@@ -1012,6 +1018,20 @@
__func__, i, d->dce, vdce, d->_vdces,
d->swap_gnd, d->vddio, d->hphl_status & 0x01,
d->_type);
+
+
+ /*
+ * If GND and MIC prongs are aligned to HPHR and GND of
+ * headphone, codec measures the voltage based on
+ * impedance between HPHR and GND which results in ~80mv.
+ * Avoid this.
+ */
+ if (d->_vdces >= WCD9XXX_MEAS_INVALD_RANGE_LOW_MV &&
+ d->_vdces <= WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV) {
+ pr_debug("%s: within invalid range\n", __func__);
+ type = PLUG_TYPE_INVALID;
+ goto exit;
+ }
}
if (ch != size && ch > 0) {
pr_debug("%s: Invalid, inconsistent HPHL\n", __func__);
@@ -1616,9 +1636,15 @@
* While we don't know whether MIC is there or not, let the resmgr know
* so micbias can be disabled temporarily
*/
- if (mbhc->current_plug == PLUG_TYPE_HEADSET)
+ if (mbhc->current_plug == PLUG_TYPE_HEADSET) {
wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
WCD9XXX_COND_HPH_MIC, false);
+ wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
+ WCD9XXX_COND_HPH, false);
+ } else if (mbhc->current_plug == PLUG_TYPE_HEADPHONE) {
+ wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
+ WCD9XXX_COND_HPH, false);
+ }
vddio = (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
mbhc->mbhc_micbias_switched);
@@ -1639,9 +1665,15 @@
if (vddio && (mbhc->current_plug == PLUG_TYPE_HEADSET))
__wcd9xxx_switch_micbias(mbhc, 1, true, true);
- if (mbhc->current_plug == PLUG_TYPE_HEADSET)
+ if (mbhc->current_plug == PLUG_TYPE_HEADSET) {
+ wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
+ WCD9XXX_COND_HPH, true);
wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
WCD9XXX_COND_HPH_MIC, true);
+ } else if (mbhc->current_plug == PLUG_TYPE_HEADPHONE) {
+ wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
+ WCD9XXX_COND_HPH, true);
+ }
WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
return IRQ_HANDLED;
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index 2011346..18614d8 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -688,7 +688,6 @@
{
struct wcd9xxx_resmgr_cond_entry *entry;
- WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
return -ENOMEM;
@@ -697,9 +696,12 @@
entry->reg = reg;
entry->shift = shift;
entry->invert = invert;
+
+ WCD9XXX_BCL_LOCK(resmgr);
list_add_tail(&entry->list, &resmgr->update_bit_cond_h);
wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
+ WCD9XXX_BCL_UNLOCK(resmgr);
return 0;
}
@@ -717,7 +719,7 @@
struct wcd9xxx_resmgr_cond_entry *e = NULL;
pr_debug("%s: enter\n", __func__);
- WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
+ WCD9XXX_BCL_LOCK(resmgr);
list_for_each_safe(l, next, &resmgr->update_bit_cond_h) {
e = list_entry(l, struct wcd9xxx_resmgr_cond_entry, list);
if (e->reg == reg && e->shift == shift && e->invert == invert) {
@@ -725,10 +727,12 @@
1 << e->shift,
e->invert << e->shift);
list_del(&e->list);
+ WCD9XXX_BCL_UNLOCK(resmgr);
kfree(e);
return 0;
}
}
+ WCD9XXX_BCL_UNLOCK(resmgr);
pr_err("%s: Cannot find update bit entry reg 0x%x, shift %d\n",
__func__, e ? e->reg : 0, e ? e->shift : 0);
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.h b/sound/soc/codecs/wcd9xxx-resmgr.h
index 53c48f6..8acc816 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr.h
@@ -193,7 +193,8 @@
const enum wcd9xxx_notify_event e);
enum wcd9xxx_resmgr_cond {
- WCD9XXX_COND_HPH_MIC = 1,
+ WCD9XXX_COND_HPH = 0x01, /* Headphone */
+ WCD9XXX_COND_HPH_MIC = 0x02, /* Microphone on the headset */
};
int wcd9xxx_resmgr_rm_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
enum wcd9xxx_resmgr_cond cond,
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index c5cfa11..4462213 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -133,6 +133,7 @@
struct msm8974_asoc_mach_data {
int mclk_gpio;
u32 mclk_freq;
+ int us_euro_gpio;
struct msm_auxpcm_ctrl *pri_auxpcm_ctrl;
};
@@ -1040,6 +1041,16 @@
slim0_rx_sample_rate_get, slim0_rx_sample_rate_put),
};
+static bool msm8974_swap_gnd_mic(struct snd_soc_codec *codec)
+{
+ struct snd_soc_card *card = codec->card;
+ struct msm8974_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ int value = gpio_get_value_cansleep(pdata->us_euro_gpio);
+ pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value);
+ gpio_set_value_cansleep(pdata->us_euro_gpio, !value);
+ return true;
+}
+
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
int err;
@@ -1984,6 +1995,25 @@
return 0;
}
+static int msm8974_prepare_us_euro(struct snd_soc_card *card)
+{
+ struct msm8974_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ int ret;
+ if (pdata->us_euro_gpio) {
+ dev_dbg(card->dev, "%s : us_euro gpio request %d", __func__,
+ pdata->us_euro_gpio);
+ ret = gpio_request(pdata->us_euro_gpio, "TAIKO_CODEC_US_EURO");
+ if (ret) {
+ dev_err(card->dev,
+ "%s: Failed to request taiko US/EURO gpio %d error %d\n",
+ __func__, pdata->us_euro_gpio, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static __devinit int msm8974_asoc_machine_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = &snd_soc_card_msm8974;
@@ -2073,6 +2103,23 @@
card->num_links = ARRAY_SIZE(msm8974_common_dai_links);
}
+ pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,us-euro-gpios", 0);
+ if (pdata->us_euro_gpio < 0) {
+ dev_err(&pdev->dev, "Looking up %s property in node %s failed",
+ "qcom,us-euro-gpios",
+ pdev->dev.of_node->full_name);
+ } else {
+ dev_dbg(&pdev->dev, "%s detected %d",
+ "qcom,us-euro-gpios", pdata->us_euro_gpio);
+ mbhc_cfg.swap_gnd_mic = msm8974_swap_gnd_mic;
+ }
+
+ ret = msm8974_prepare_us_euro(card);
+ if (ret)
+ dev_err(&pdev->dev, "msm8974_prepare_us_euro failed (%d)\n",
+ ret);
+
mutex_init(&cdc_mclk_mutex);
atomic_set(&auxpcm_rsc_ref, 0);
spdev = pdev;
@@ -2094,6 +2141,18 @@
}
return 0;
err:
+ if (pdata->mclk_gpio > 0) {
+ dev_dbg(&pdev->dev, "%s free gpio %d\n",
+ __func__, pdata->mclk_gpio);
+ gpio_free(pdata->mclk_gpio);
+ pdata->mclk_gpio = 0;
+ }
+ if (pdata->us_euro_gpio > 0) {
+ dev_dbg(&pdev->dev, "%s free us_euro gpio %d\n",
+ __func__, pdata->us_euro_gpio);
+ gpio_free(pdata->us_euro_gpio);
+ pdata->us_euro_gpio = 0;
+ }
devm_kfree(&pdev->dev, pdata);
return ret;
}
@@ -2107,6 +2166,7 @@
regulator_put(ext_spk_amp_regulator);
gpio_free(pdata->mclk_gpio);
+ gpio_free(pdata->us_euro_gpio);
if (ext_spk_amp_gpio >= 0)
gpio_free(ext_spk_amp_gpio);
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index 4c50b53..f030d3c 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -1354,10 +1354,17 @@
for (i = 0; i < num_copps; i++)
send_adm_cal(port_id[i], path);
- for (i = 0; i < num_copps; i++)
- rtac_add_adm_device(port_id[i], atomic_read(&this_adm.copp_id
- [afe_get_port_index(port_id[i])]),
- path, session_id);
+ for (i = 0; i < num_copps; i++) {
+ int tmp;
+ tmp = afe_get_port_index(port_id[i]);
+ if (tmp >= 0 && tmp < AFE_MAX_PORTS)
+ rtac_add_adm_device(port_id[i],
+ atomic_read(&this_adm.copp_id[tmp]),
+ path, session_id);
+ else
+ pr_debug("%s: Invalid port index %d",
+ __func__, tmp);
+ }
return 0;
fail_cmd:
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 1f2f307..b32daaa 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -1017,10 +1017,17 @@
for (i = 0; i < num_copps; i++)
send_adm_cal(port_id[i], path);
- for (i = 0; i < num_copps; i++)
- rtac_add_adm_device(port_id[i], atomic_read(&this_adm.copp_id
- [afe_get_port_index(port_id[i])]),
- path, session_id);
+ for (i = 0; i < num_copps; i++) {
+ int tmp;
+ tmp = afe_get_port_index(port_id[i]);
+ if (tmp >= 0 && tmp < AFE_MAX_PORTS)
+ rtac_add_adm_device(port_id[i],
+ atomic_read(&this_adm.copp_id[tmp]),
+ path, session_id);
+ else
+ pr_debug("%s: Invalid port index %d",
+ __func__, tmp);
+ }
fail_cmd:
kfree(matrix_map);