Merge "input: touchpanel: Move Goodix GT915 driver to drivers folder"
diff --git a/Documentation/devicetree/bindings/bif/qpnp-bsi.txt b/Documentation/devicetree/bindings/bif/qpnp-bsi.txt
index 29267dd..0ff10a4 100644
--- a/Documentation/devicetree/bindings/bif/qpnp-bsi.txt
+++ b/Documentation/devicetree/bindings/bif/qpnp-bsi.txt
@@ -49,6 +49,7 @@
- qcom,vref-microvolts: Reference voltage used for BCL divider circuit in
microvolts. If no value is specified, then
1800000 uV is assumed.
+- qcom,bsi-vadc: Corresponding VADC device phandle.
All properties specified within for the BIF framework can also be used. These
properties can be found in bif.txt.
@@ -86,6 +87,7 @@
qcom,channel-num = <0x31>;
qcom,pullup-ohms = <100000>;
qcom,vref-microvolts = <1800000>;
+ qcom,bsi-vadc = <&pm8941_vadc>;
};
};
};
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
index 418447d..39be71e 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
@@ -24,6 +24,12 @@
Channel node
NOTE: Atleast one Channel node is required.
+Client required property:
+- qcom,<consumer name>-iadc : The phandle to the corresponding iadc device.
+ The consumer name passed to the driver when calling
+ qpnp_get_iadc() is used to associate the client
+ with the corresponding device.
+
Required properties:
- label : Channel name used for sysfs entry.
- reg : AMUX channel number.
@@ -84,6 +90,8 @@
6 : 64
7 : 128
8 : 256
+- qcom,iadc-vadc : Corresponding phandle of the VADC device to read the die_temperature and set
+ simultaneous voltage and current conversion requests.
Example:
/* Main Node */
@@ -97,6 +105,7 @@
qcom,adc-bit-resolution = <16>;
qcom,adc-vdd-reference = <1800>;
qcom,rsense = <1500>;
+ qcom,iadc-vadc = <&pm8941_vadc>;
/* Channel Node */
chan@0 = {
@@ -110,3 +119,9 @@
qcom,fast-avg-setup = <0>;
};
};
+
+Client device example:
+/* Add to the clients node that needs the IADC */
+client_node {
+ qcom,client-iadc = <&pm8941_iadc>;
+};
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
index 8de8bdd..7f34a8f 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
@@ -20,6 +20,12 @@
Channel nodes
NOTE: Atleast one Channel node is required.
+Client required property:
+- qcom,<consumer name>-vadc : The phandle to the corresponding vadc device.
+ The consumer name passed to the driver when calling
+ qpnp_get_vadc() is used to associate the client
+ with the corresponding device.
+
Required properties:
- label : Channel name used for sysfs entry.
- reg : AMUX channel number.
@@ -113,6 +119,12 @@
};
};
+Client device example:
+/* Add to the clients node that needs the VADC channel A/D */
+client_node {
+ qcom,client-vadc = <&pm8941_vadc>;
+};
+
/* 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
diff --git a/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt b/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
index 3720172..0f35e73 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
@@ -20,7 +20,6 @@
- synaptics,panel-x : panel x dimension
- synaptics,panel-y : panel y dimension
- synaptics,fw-image-name : name of firmware .img file in /etc/firmware
- - synaptics,power-down : fully power down regulators in suspend
Example:
i2c@f9927000 { /* BLSP1 QUP5 */
diff --git a/Documentation/devicetree/bindings/media/video/msm-ispif.txt b/Documentation/devicetree/bindings/media/video/msm-ispif.txt
index ff33b17..dc1187a 100644
--- a/Documentation/devicetree/bindings/media/video/msm-ispif.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-ispif.txt
@@ -4,6 +4,7 @@
- cell-index: ispif hardware core index
- compatible :
- "qcom,ispif"
+ - "qcom,ispif-v3.0"
- reg : offset and length of the register set for the device
for the ispif operating in compatible mode.
- reg-names : should specify relevant names to each reg property defined.
@@ -11,9 +12,13 @@
- interrupt-names : should specify relevant names to each interrupts
property defined.
+Optional properties:
+- qcom,num-isps: The number of ISPs the ISPIF module is connected to. If not set
+ the default value used is 1
+
Example:
- qcom,ispif@0xfda0a000 {
+ qcom,ispif@fda0a000 {
cell-index = <0>;
compatible = "qcom,ispif";
reg = <0xfda0a000 0x300>;
@@ -21,3 +26,16 @@
interrupts = <0 55 0>;
interrupt-names = "ispif";
};
+
+or
+
+ qcom,ispif@fda0a000 {
+ cell-index = <0>;
+ compatible = "qcom,ispif-v3.0", "qcom,ispif";
+ reg = <0xfda0a000 0x300>;
+ reg-names = "ispif";
+ interrupts = <0 55 0>;
+ interrupt-names = "ispif";
+ qcom,num-isps = <2>
+ };
+
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
index ac60e38..cc2506d 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -33,15 +33,31 @@
request by different video encoder usecases.
- qcom,dec-ddr-ab-ib : list of bus vectors(ab, ib pair) for ddr bandwidth
request by different video decoder usecases.
-- qcom,iommu-groups : list of IOMMU groups to be used. Groups are defined as
- phandles in <target>-iommu-domains.dtsi (e.g msm8974-v1-iommu-domains.dtsi)
-- qcom,iommu-group-buffer-types : bitmap of buffer types that can be mapped into
- the corresponding IOMMU group. Buffer types are defined within the vidc driver
- by "enum hal_buffer" in msm_smem.h
- qcom,buffer-type-tz-usage-table : a key-value pair, mapping a buffer type
(enum hal_buffer) to its corresponding TZ usage. The TZ usages are defined
as "enum cp_mem_usage" in include/linux/msm_ion.h
- qcom,has-ocmem: indicate the target has ocmem if this property exists
+- qcom,vidc-iommu-domains: node containing individual domain nodes, each with:
+ - a unique domain name for the domain node (e.g vidc,domain-ns)
+ - qcom,vidc-domain-phandle: phandle for the domain as defined in
+ <target>-iommu-domains.dtsi (e.g msm8974-v1-iommu-domains.dtsi)
+ - qcom,vidc-partition-buffer-types: bitmap of buffer types that can
+ be mapped into each IOMMU domain partition. There must be exactly
+ one buffer bitmap per partition in the domain, with order of the
+ bitmaps to be the same as the order of the respective partitions.
+ - Buffer types are defined as the following:
+ input = 0x1
+ output = 0x2
+ output2 = 0x2
+ extradata input = 0x4
+ extradata output = 0x8
+ extradata output2 = 0x8
+ internal scratch = 0x10
+ internal scratch1 = 0x20
+ internal scratch2 = 0x40
+ internal persist = 0x80
+ internal persist1 = 0x100
+ internal cmd queue = 0x200
Example:
@@ -71,9 +87,20 @@
<60000 664950>;
qcom,dec-ddr-ab-ib = <0 0>,
<110000 909000>;
- qcom,iommu-groups = <&venus_domain_ns &venus_domain_cp>;
- qcom,iommu-group-buffer-types = <0xfff 0x1ff>;
qcom,buffer-type-tz-usage-table = <0x1 0x1>,
<0x1fe 0x2>;
qcom,max-hw-load = <1224450>; /* 4k @ 30 + 1080p @ 30*/
+ qcom,vidc-iommu-domains {
+ qcom,domain-ns {
+ qcom,vidc-domain-phandle = <&venus_domain_ns>;
+ qcom,vidc-partition-buffer-types = <0x1ff>,
+ <0x200>;
+ };
+
+ qcom,domain-cp {
+ qcom,vidc-domain-phandle = <&venus_domain_cp>;
+ qcom,vidc-partition-buffer-types = <0x2>,
+ <0x1f1>;
+ };
+ };
};
diff --git a/Documentation/devicetree/bindings/power/qpnp-bms.txt b/Documentation/devicetree/bindings/power/qpnp-bms.txt
index 0672f14..1162298 100644
--- a/Documentation/devicetree/bindings/power/qpnp-bms.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-bms.txt
@@ -86,6 +86,8 @@
for storing the FCC(mAh) in the 8-bit BMS register.
For example - A value of 10 indicates:
FCC value (in mAh) = (8-bit register value) * 10.
+- qcom,bms-vadc: Corresponding VADC device's phandle.
+- qcom,bms-iadc: Corresponding IADC device's phandle.
Parent node optional properties:
- qcom,ignore-shutdown-soc: A boolean that controls whether BMS will
@@ -101,6 +103,8 @@
- qcom,use-ocv-thresholds : A boolean that controls whether BMS will take
new OCVs only between the defined thresholds.
- qcom,enable-fcc-learning: A boolean that defines if FCC learning is enabled.
+- qcom,bms-adc_tm: Corresponding ADC_TM device's phandle to set recurring measurements
+ and receive notifications for die_temperature, vbatt.
All sub node required properties:
@@ -148,6 +152,9 @@
qcom,hold-soc-est = <3>;
qcom,tm-temp-margin = <5000>;
qcom,battery-data = <&mtp_batterydata>;
+ qcom,bms-vadc = <&pm8941_vadc>;
+ qcom,bms-iadc = <&pm8941_iadc>;
+ qcom,bms-adc_tm = <&pm8941_adc_tm>;
qcom,bms-iadc@3800 {
reg = <0x3800 0x100>;
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index e3c3555..4a5e58c 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -80,6 +80,7 @@
for the boost regulator.
- qcom,resume-soc Capacity in percent at which charging should resume
when a fully charged battery drops below this level.
+- qcom,chg-vadc Corresponding VADC device's phandle.
Sub node required structure:
- A qcom,chg node must be a child of an SPMI node that has specified
@@ -88,6 +89,8 @@
to the collective charging device. For example USB detection
and the battery interface are each seperate peripherals and
each should be their own subnode.
+- qcom,chg-adc_tm Corresponding ADC TM device's phandle to set recurring
+ measurements and receive notification for batt_therm.
Sub node required properties:
- compatible: Must be "qcom,qpnp-charger".
@@ -102,6 +105,7 @@
qcom,usb-chgpth:
- usbin-valid
+ - usb-ocp (only for SMBBP and SMBCL)
qcom,chgr:
- chg-done
@@ -148,6 +152,9 @@
- coarse-det-usb: Coarse detect interrupt triggers
at low voltage on USB_IN.
- chg-gone: Triggers on VCHG line.
+ - usb-ocp Triggers on over current conditions when
+ reverse boosting. (Only available on
+ SMBCL and SMBBP devices).
qcom,dc-chgpth:
- dcin-valid: Indicates a valid DC charger
@@ -196,6 +203,8 @@
qcom,batt-hot-percent = <25>;
qcom,batt-cold-percent = <85>;
qcom,btc-disabled = <0>;
+ qcom,chg-vadc = <&pm8941_vadc>;
+ qcom,chg-adc_tm = <&pm8941_adc_tm>;
qcom,chgr@1000 {
reg = <0x1000 0x100>;
diff --git a/Documentation/devicetree/bindings/regulator/krait-regulator-pmic.txt b/Documentation/devicetree/bindings/regulator/krait-regulator-pmic.txt
new file mode 100644
index 0000000..a0730f6
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/krait-regulator-pmic.txt
@@ -0,0 +1,47 @@
+Krait Voltage regulators in the PMIC
+
+In certain MSMs the CPUs are powered using a single supply powered by PMIC ganged regulators
+operating in different phases. The krait-regulator-pmic node represents the gang leader and its
+associated control, power stage and frequency peripherals.
+
+[First Level Nodes]
+Required properties:
+- compatible: Must be "qcom,krait-regulator-pmic".
+- spmi-dev-container: Specifies that all the device nodes specified
+ within this node should have their resources coalesced into a
+ single spmi_device. This is used to specify all SPMI peripherals
+ that logically make up the gang leader.
+ - #address-cells: The number of cells dedicated to represent an address
+ This must be set to '1'.
+ - #size-cells: The number of cells dedicated to represent address
+ space range of a peripheral. This must be set to '1'.
+
+[Second Level Nodes]
+Required properties:
+- reg: Specifies the SPMI address and size for this peripheral.
+There must be exactly three subnodes qcom,ctl qcom,ps and qcom,freq representing control,
+power stage and frequency SPMI peripherals respectively of the gang leader.
+
+Example:
+ krait_regulator_pmic: qcom,krait-regulator-pmic {
+ spmi-dev-container;
+ compatible = "qcom,krait-regulator-pmic";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+
+ qcom,ctl@2000 {
+ status = "disabled";
+ reg = <0x2000 0x100>;
+ };
+
+ qcom,ps@2100 {
+ status = "disabled";
+ reg = <0x2100 0x100>;
+ };
+
+ qcom,freq@2200 {
+ status = "disabled";
+ reg = <0x2200 0x100>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
index 3854598..e1681ca 100644
--- a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
+++ b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
@@ -27,6 +27,12 @@
crosses a set threshold, read temperature and enable/set trip types supported
by the thermal framework.
+Client required property:
+- qcom,<consumer name>-adc_tm : The phandle to the corresponding adc_tm device.
+ The consumer name passed to the driver when calling
+ qpnp_get_adc_tm() is used to associate the client
+ with the corresponding device.
+
Channel nodes
NOTE: Atleast one Channel node is required.
@@ -95,6 +101,13 @@
8 : 256
- qcom,btm-channel-number : There are 5 BTM channels. The BTM channel numbers are statically
allocated to the corresponding channel node.
+- qcom,adc_tm-vadc : phandle to the corresponding VADC device to read the ADC channels.
+
+Client device example:
+/* Add to the clients node that needs the ADC_TM channel A/D */
+client_node {
+ qcom,client-adc_tm = <&pm8941_adc_tm>;
+};
Example:
/* Main Node */
@@ -111,6 +124,7 @@
"low-thr-en-set";
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
+ qcom,adc_tm-vadc = <&pm8941_vadc>;
/* Channel Node to be registered as part of thermal sysfs */
chan@b5 {
diff --git a/Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt b/Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt
index 19fbd3a..1c42692 100644
--- a/Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt
+++ b/Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt
@@ -37,6 +37,7 @@
- qcom,default-temp: Specifies the default temperature in millicelcius to use
if no ADC channel is present to read the real time
temperature.
+- qcom,temp_alarm-vadc: Corresponding VADC device's phandle.
Note, if a given optional qcom,* binding is not present, then the default
hardware state for that feature will be maintained.
@@ -61,6 +62,7 @@
label = "pm8941_tz";
qcom,channel-num = <8>;
qcom,threshold-set = <0>;
+ qcom,temp_alarm-vadc = <&pm8941_vadc>;
};
};
};
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index f2707f6..b93dc4d 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -39,7 +39,11 @@
- hsic,data-pad-offset : Offset of TLMM register for configuring HSIC
DATA GPIO PAD.
- qcom,phy-sof-workaround : If present then HSIC PHY has h/w BUGs related to
- SOFs. Software workarounds are required for the same.
+ SOFs. All the relevant software workarounds are required for the same during
+ suspend, reset and resume.
+- qcom,phy-susp-sof-workaround : If present then HSIC PHY has h/w BUG related to
+ SOFs while entering SUSPEND. Relevant software workaround is required for the same
+ during SUSPEND only.
- qcom,pool-64-bit-align: If present then the pool's memory will be aligned
to 64 bits
- qcom,enable_hbm: if present host bus manager is enabled.
diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
index ff7b03d..f2a9940 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -49,6 +49,9 @@
is not supported and attached host should always be assumed as SDP.
- USB3_GDSC-supply : phandle to the globally distributed switch controller
regulator node to the USB controller.
+- qcom,dwc_usb3-adc_tm: Corresponding ADC_TM device's phandle to set recurring
+ measurements on USB_ID channel when using ADC and receive
+ notifications for set thresholds.
Sub nodes:
- Sub node for "DWC3- USB3 controller".
@@ -72,6 +75,7 @@
qcom,dwc-usb3-msm-dbm-eps = <4>
qcom,vdd-voltage-level = <1 5 7>;
qcom,dwc-hsphy-init = <0x00D195A4>;
+ qcom,dwc_usb3-adc_tm = <&pm8941_adc_tm>;
qcom,msm_bus,name = "usb3";
qcom,msm_bus,num_cases = <2>;
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index 53e9b3b..acd0bb9 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -90,6 +90,7 @@
hsic,ignore-cal-pad-config;
hsic,strobe-pad-offset = <0x2050>;
hsic,data-pad-offset = <0x2054>;
+ qcom,phy-susp-sof-workaround;
qcom,msm-bus,name = "hsic";
qcom,msm-bus,num-cases = <2>;
diff --git a/arch/arm/boot/dts/apq8074-v2.2-cdp.dts b/arch/arm/boot/dts/apq8074-v2.2-cdp.dts
new file mode 100644
index 0000000..a3dc490
--- /dev/null
+++ b/arch/arm/boot/dts/apq8074-v2.2-cdp.dts
@@ -0,0 +1,34 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "apq8074-v2.2.dtsi"
+/include/ "msm8974-cdp.dtsi"
+
+/ {
+ model = "Qualcomm APQ 8074v2.2 CDP";
+ compatible = "qcom,apq8074-cdp", "qcom,apq8074", "qcom,cdp";
+ qcom,msm-id = <184 1 0x20002>;
+};
+
+&usb3 {
+ interrupt-parent = <&usb3>;
+ interrupts = <0 1>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0x0 0xffffffff>;
+ interrupt-map = <0x0 0 &intc 0 133 0
+ 0x0 1 &spmi_bus 0x0 0x0 0x9 0x0>;
+ interrupt-names = "hs_phy_irq", "pmic_id_irq";
+
+ qcom,misc-ref = <&pm8941_misc>;
+};
diff --git a/arch/arm/boot/dts/apq8074-v2.2-dragonboard.dts b/arch/arm/boot/dts/apq8074-v2.2-dragonboard.dts
new file mode 100644
index 0000000..6989088
--- /dev/null
+++ b/arch/arm/boot/dts/apq8074-v2.2-dragonboard.dts
@@ -0,0 +1,22 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "apq8074-v2.2.dtsi"
+/include/ "apq8074-dragonboard.dtsi"
+
+/ {
+ model = "Qualcomm APQ 8074v2.2 DRAGONBOARD";
+ compatible = "qcom,apq8074-dragonboard", "qcom,apq8074", "qcom,dragonboard";
+ qcom,msm-id = <184 10 0x20002>;
+};
diff --git a/arch/arm/boot/dts/apq8074-v2.2-liquid.dts b/arch/arm/boot/dts/apq8074-v2.2-liquid.dts
new file mode 100644
index 0000000..09d6e66
--- /dev/null
+++ b/arch/arm/boot/dts/apq8074-v2.2-liquid.dts
@@ -0,0 +1,22 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "apq8074-v2.2.dtsi"
+/include/ "msm8974-liquid.dtsi"
+
+/ {
+ model = "Qualcomm APQ 8074v2.2 LIQUID";
+ compatible = "qcom,apq8074-liquid", "qcom,apq8074", "qcom,liquid";
+ qcom,msm-id = <184 9 0x20002>;
+};
diff --git a/arch/arm/boot/dts/apq8074-v2.2.dtsi b/arch/arm/boot/dts/apq8074-v2.2.dtsi
new file mode 100644
index 0000000..ddf7ec8
--- /dev/null
+++ b/arch/arm/boot/dts/apq8074-v2.2.dtsi
@@ -0,0 +1,57 @@
+/* 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.
+ */
+
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm8974.dtsi file.
+ */
+
+/include/ "msm8974-v2.2.dtsi"
+
+&soc {
+ qcom,qseecom@a700000 {
+ compatible = "qcom,qseecom";
+ reg = <0x0a700000 0x500000>;
+ reg-names = "secapp-region";
+ qcom,disk-encrypt-pipe-pair = <2>;
+ qcom,hlos-ce-hw-instance = <1>;
+ qcom,qsee-ce-hw-instance = <0>;
+ qcom,msm-bus,name = "qseecom-noc";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,active-only = <0>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <55 512 0 0>,
+ <55 512 3936000 393600>,
+ <55 512 3936000 393600>,
+ <55 512 3936000 393600>;
+ };
+
+ sound {
+ compatible = "qcom,apq8074-audio-taiko";
+ };
+};
+
+&memory_hole {
+ qcom,memblock-remove = <0x0a700000 0x5800000>; /* Address and size of the hole */
+};
+
+&qseecom {
+ status = "disabled";
+};
+
+&sdcc3 {
+ qcom,sup-voltages = <2000 2000>;
+ status = "ok";
+};
+
diff --git a/arch/arm/boot/dts/apq8084-regulator.dtsi b/arch/arm/boot/dts/apq8084-regulator.dtsi
index 0c9ca7d..3d5fc7c 100644
--- a/arch/arm/boot/dts/apq8084-regulator.dtsi
+++ b/arch/arm/boot/dts/apq8084-regulator.dtsi
@@ -326,9 +326,9 @@
};
&rpm_bus {
- rpm-regulator-smpb1 {
+ rpm-regulator-smpa1 {
compatible = "qcom,rpm-regulator-smd-resource";
- qcom,resource-name = "smpb";
+ qcom,resource-name = "smpa";
qcom,resource-id = <1>;
qcom,regulator-type = <1>;
qcom,hpm-min-load = <100000>;
@@ -342,9 +342,9 @@
};
};
- rpm-regulator-smpb2 {
+ rpm-regulator-smpa2 {
compatible = "qcom,rpm-regulator-smd-resource";
- qcom,resource-name = "smpb";
+ qcom,resource-name = "smpa";
qcom,resource-id = <2>;
qcom,regulator-type = <1>;
qcom,hpm-min-load = <100000>;
diff --git a/arch/arm/boot/dts/mpq8092-iommu.dtsi b/arch/arm/boot/dts/mpq8092-iommu.dtsi
index baec2d5..320440c 100644
--- a/arch/arm/boot/dts/mpq8092-iommu.dtsi
+++ b/arch/arm/boot/dts/mpq8092-iommu.dtsi
@@ -27,23 +27,19 @@
0x215c
0x220c
0x22bc
- 0x2008
- 0x200c
- 0x2010>;
+ 0x2008>;
- qcom,iommu-bfb-data = <0x3FFF
+ qcom,iommu-bfb-data = <0x0F
0x4
0x4
0x0
0x0
- 0x10
- 0x50
+ 0x4
+ 0x14
0x0
- 0x2000
- 0x2804
- 0x9614
- 0x0
- 0x0
+ 0x800
+ 0x800
+ 0x3a04
0x0
0x0>;
};
@@ -66,21 +62,19 @@
0x2008
0x200c
0x2010
- 0x2014
- 0x2018>;
+ 0x2014>;
- qcom,iommu-bfb-data = <0x7FFFFF
+ qcom,iommu-bfb-data = <0x3FFFF
0x4
- 0x10
+ 0x4
0x0
- 0x5000
- 0x5a1d
- 0x1822d
+ 0x1000
+ 0x0e00
+ 0x8207
0x0
0x0
- 0x28
- 0x68
- 0x0
+ 0x8
+ 0x24
0x0
0x0
0x0
@@ -114,9 +108,9 @@
0x4
0x8
0x0
- 0x13607
- 0x4201
- 0x14221
+ 0x13205
+ 0x4000
+ 0x14020
0x0
0x0
0x94
@@ -184,10 +178,13 @@
0x2620
0x2624
0x2628
- 0x262c>;
+ 0x262c
+ 0x2630
+ 0x2634
+ 0x2638>;
qcom,iommu-bfb-data = <0x3
- 0x8
+ 0x4
0x10
0x0
0x0
@@ -196,26 +193,79 @@
0x0
0x0
0x1
- 0x101
+ 0x81
0x0
0x0
- 0x7
+ 0x1f
0x4
0x8
0x14
0x0
0x0
0xc
- 0x6c
+ 0x3c
0x0
- 0x8
+ 0x4
0x10
- 0x0>;
+ 0x0
+ 0x15
+ 0x3020100
+ 0x04>;
};
&vpu_iommu {
status = "ok";
+ qcom,iommu-bfb-regs = <0x204c
+ 0x2050
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2008
+ 0x200c
+ 0x2010
+ 0x2014
+ 0x2018
+ 0x201c
+ 0x2020
+ 0x2024
+ 0x2028
+ 0x202c
+ 0x2030>;
+
+ qcom,iommu-bfb-data = <0xffffffff
+ 0xfffff
+ 0x4
+ 0x8
+ 0x0
+ 0x0
+ 0x34
+ 0x104
+ 0x0
+ 0x6800
+ 0x6800
+ 0x18034
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0>;
+
interrupts = <0 300 0>;
vpu_cb_0: qcom,iommu-ctx@fdeec000 {
interrupts = <0 302 0>;
@@ -229,3 +279,7 @@
interrupts = <0 302 0>;
};
};
+
+&vcap_iommu {
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/mpq8092-rumi.dts b/arch/arm/boot/dts/mpq8092-rumi.dts
index 1abaf55..3ba2fbc 100644
--- a/arch/arm/boot/dts/mpq8092-rumi.dts
+++ b/arch/arm/boot/dts/mpq8092-rumi.dts
@@ -18,7 +18,7 @@
/ {
model = "Qualcomm MPQ8092 RUMI";
compatible = "qcom,mpq8092-rumi", "qcom,mpq8092", "qcom,rumi";
- qcom,msm-id = <146 16 0>;
+ qcom,msm-id = <146 15 0>;
};
&soc {
diff --git a/arch/arm/boot/dts/mpq8092-rumi.dtsi b/arch/arm/boot/dts/mpq8092-rumi.dtsi
index cc345d8..af49eaf 100644
--- a/arch/arm/boot/dts/mpq8092-rumi.dtsi
+++ b/arch/arm/boot/dts/mpq8092-rumi.dtsi
@@ -10,6 +10,12 @@
* GNU General Public License for more details.
*/
+/ {
+ aliases {
+ spi0 = &spi_0;
+ };
+};
+
&soc {
timer {
clock-frequency = <5000000>;
@@ -41,17 +47,28 @@
status = "disable";
};
- spi@f9923000 {
+ spi_0: spi@f9923000 { /* BLSP1 QUP1 */
compatible = "qcom,spi-qup-v2";
- reg = <0xf9923000 0x1000>;
- interrupts = <0 95 0>;
- spi-max-frequency = <24000000>;
#address-cells = <1>;
#size-cells = <0>;
- gpios = <&msmgpio 3 0>, /* CLK */
- <&msmgpio 1 0>, /* MISO */
- <&msmgpio 0 0>; /* MOSI */
- cs-gpios = <&msmgpio 9 0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0xf9923000 0x1000>,
+ <0xf9904000 0xf000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 95 0>, <0 238 0>;
+ spi-max-frequency = <19200000>;
+
+ qcom,gpio-mosi = <&msmgpio 0 0>;
+ qcom,gpio-miso = <&msmgpio 1 0>;
+ qcom,gpio-clk = <&msmgpio 3 0>;
+ qcom,gpio-cs2 = <&msmgpio 11 0>;
+
+ qcom,infinite-mode = <0>;
+ qcom,use-bam;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <12>;
+ qcom,bam-producer-pipe-index = <13>;
+ qcom,master-id = <86>;
ethernet-switch@2 {
compatible = "simtec,ks8851";
diff --git a/arch/arm/boot/dts/mpq8092-sim.dts b/arch/arm/boot/dts/mpq8092-sim.dts
index 676ef3b..2384a45 100644
--- a/arch/arm/boot/dts/mpq8092-sim.dts
+++ b/arch/arm/boot/dts/mpq8092-sim.dts
@@ -17,7 +17,7 @@
/ {
model = "Qualcomm MPQ8092 Simulator";
compatible = "qcom,mpq8092-sim", "qcom,mpq8092", "qcom,sim";
- qcom,msm-id = <126 16 0>;
+ qcom,msm-id = <146 16 0>;
};
&soc {
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index 2f67f3e..52bcb2c 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -308,5 +308,9 @@
status = "ok";
};
+&gdsc_vcap {
+ status = "ok";
+};
+
/include/ "msm-pma8084.dtsi"
/include/ "mpq8092-regulator.dtsi"
diff --git a/arch/arm/boot/dts/msm-gdsc.dtsi b/arch/arm/boot/dts/msm-gdsc.dtsi
index 495f65a..2f732a4 100644
--- a/arch/arm/boot/dts/msm-gdsc.dtsi
+++ b/arch/arm/boot/dts/msm-gdsc.dtsi
@@ -109,4 +109,11 @@
reg = <0xfc401ec0 0x4>;
status = "disabled";
};
+
+ gdsc_vcap: qcom,gdsc@fd8c1804 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_vcap";
+ reg = <0xfd8c1804 0x4>;
+ status = "disabled";
+ };
};
diff --git a/arch/arm/boot/dts/msm-iommu-v1.dtsi b/arch/arm/boot/dts/msm-iommu-v1.dtsi
index ef8677d..cd5adaa 100644
--- a/arch/arm/boot/dts/msm-iommu-v1.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v1.dtsi
@@ -1056,4 +1056,98 @@
label = "lpass_core_cb_2";
};
};
+
+ vcap_iommu: qcom,iommu@fdfb6000 {
+ compatible = "qcom,msm-smmu-v1";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ reg = <0xfdfb6000 0x10000>;
+ reg-names = "iommu_base";
+ interrupts = <0 315 0>;
+ qcom,needs-alt-core-clk;
+ label = "vcap_iommu";
+ status = "disabled";
+ qcom,msm-bus,name = "vcap_ebi";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <48 512 0 0>,
+ <48 512 0 1000>;
+
+ qcom,iommu-pmu-ngroups = <1>;
+ qcom,iommu-pmu-ncounters = <8>;
+ qcom,iommu-pmu-event-classes = <0x00
+ 0x01
+ 0x08
+ 0x09
+ 0x0A
+ 0x10
+ 0x11
+ 0x12
+ 0x80
+ 0x81
+ 0x82
+ 0x83
+ 0x90
+ 0x91
+ 0x92
+ 0xb0
+ 0xb1>;
+
+ qcom,iommu-bfb-regs = <0x204c
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2494
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x22bc
+ 0x2008
+ 0x200c>;
+
+ qcom,iommu-bfb-data = <0x0ff
+ 0x00000004
+ 0x00000008
+ 0x0
+ 0x0
+ 0x00000008
+ 0x00000028
+ 0x0
+ 0x001000
+ 0x001000
+ 0x003008
+ 0x0
+ 0x0
+ 0x0>;
+
+ qcom,iommu-ctx@fdfbe000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xfdfbe000 0x1000>;
+ interrupts = <0 313 0>;
+ qcom,iommu-ctx-sids = <0>;
+ label = "vcap_cb0";
+ };
+
+ qcom,iommu-ctx@fdfbf000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xfdfbf000 0x1000>;
+ interrupts = <0 313 0>;
+ qcom,iommu-ctx-sids = <1>;
+ label = "vcap_cb1";
+ };
+
+ qcom,iommu-ctx@fdfc0000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
+ reg = <0xfdfc0000 0x1000>;
+ interrupts = <0 313 0>;
+ qcom,iommu-ctx-sids = <>;
+ label = "vcap_cb2";
+ };
+ };
};
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 4f3e461..1d7eaa5 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -59,15 +59,17 @@
qcom,vddmax-mv = <4200>;
qcom,vddsafe-mv = <4230>;
- qcom,vinmin-mv = <4200>;
+ qcom,vinmin-mv = <4300>;
qcom,vbatdet-mv = <4100>;
qcom,ibatmax-ma = <1500>;
qcom,ibatterm-ma = <100>;
qcom,ibatsafe-ma = <1500>;
qcom,thermal-mitigation = <1500 700 600 325>;
- qcom,vbatdet-delta-mv = <350>;
+ qcom,vbatdet-delta-mv = <100>;
qcom,resume-soc = <99>;
qcom,tchg-mins = <150>;
+ qcom,chg-vadc = <&pm8110_vadc>;
+ qcom,chg-adc_tm = <&pm8110_adc_tm>;
qcom,chgr@1000 {
status = "disabled";
@@ -132,11 +134,13 @@
reg = <0x1300 0x100>;
interrupts = <0 0x13 0x0>,
<0 0x13 0x1>,
- <0x0 0x13 0x2>;
+ <0x0 0x13 0x2>,
+ <0x0 0x13 0x3>;
interrupt-names = "coarse-det-usb",
"usbin-valid",
- "chg-gone";
+ "chg-gone",
+ "usb-ocp";
};
qcom,chg-misc@1600 {
@@ -249,7 +253,7 @@
};
};
- iadc@3600 {
+ pm8110_iadc: iadc@3600 {
compatible = "qcom,qpnp-iadc";
reg = <0x3600 0x100>;
#address-cells = <1>;
@@ -258,6 +262,7 @@
interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <16>;
qcom,adc-vdd-reference = <1800>;
+ qcom,iadc-vadc = <&pm8110_vadc>;
chan@0 {
label = "internal_rsense";
@@ -284,6 +289,7 @@
"low-thr-en-set";
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
+ qcom,adc_tm-vadc = <&pm8110_vadc>;
};
qcom,temp-alarm@2400 {
@@ -293,6 +299,7 @@
label = "pm8110_tz";
qcom,channel-num = <8>;
qcom,threshold-set = <0>;
+ qcom,temp_alarm-vadc = <&pm8110_vadc>;
};
pm8110_bms: qcom,bms {
@@ -320,6 +327,9 @@
qcom,low-ocv-correction-limit-uv = <100>;
qcom,high-ocv-correction-limit-uv = <50>;
qcom,hold-soc-est = <3>;
+ qcom,bms-vadc = <&pm8110_vadc>;
+ qcom,bms-iadc = <&pm8110_iadc>;
+ qcom,bms-adc_tm = <&pm8110_adc_tm>;
qcom,bms-iadc@3800 {
reg = <0x3800 0x100>;
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index d7c2155..307e4c7 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -75,14 +75,16 @@
qcom,vddmax-mv = <4200>;
qcom,vddsafe-mv = <4230>;
- qcom,vinmin-mv = <4200>;
- qcom,vbatdet-delta-mv = <150>;
+ qcom,vinmin-mv = <4300>;
+ qcom,vbatdet-delta-mv = <100>;
qcom,ibatmax-ma = <1500>;
qcom,ibatterm-ma = <100>;
qcom,ibatsafe-ma = <1500>;
qcom,thermal-mitigation = <1500 700 600 325>;
qcom,resume-soc = <99>;
qcom,tchg-mins = <150>;
+ qcom,chg-vadc = <&pm8226_vadc>;
+ qcom,chg-adc_tm = <&pm8226_adc_tm>;
qcom,chgr@1000 {
status = "disabled";
@@ -140,19 +142,6 @@
"bat-fet-on",
"vcp-on",
"psi";
-
- };
-
- pm8226_chg_otg: qcom,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";
};
pm8226_chg_boost: qcom,boost@1500 {
@@ -165,6 +154,21 @@
"limit-error";
};
+
+ pm8226_chg_otg: qcom,usb-chgpth@1300 {
+ status = "disabled";
+ reg = <0x1300 0x100>;
+ interrupts = <0 0x13 0x0>,
+ <0 0x13 0x1>,
+ <0x0 0x13 0x2>,
+ <0x0 0x13 0x3>;
+
+ interrupt-names = "coarse-det-usb",
+ "usbin-valid",
+ "chg-gone",
+ "usb-ocp";
+ };
+
qcom,chg-misc@1600 {
status = "disabled";
reg = <0x1600 0x100>;
@@ -196,6 +200,9 @@
qcom,high-ocv-correction-limit-uv = <50>;
qcom,hold-soc-est = <3>;
qcom,low-voltage-threshold = <3420000>;
+ qcom,bms-vadc = <&pm8226_vadc>;
+ qcom,bms-iadc = <&pm8226_iadc>;
+ qcom,bms-adc_tm = <&pm8226_adc_tm>;
qcom,bms-iadc@3800 {
reg = <0x3800 0x100>;
@@ -396,7 +403,7 @@
};
};
- iadc@3600 {
+ pm8226_iadc: iadc@3600 {
compatible = "qcom,qpnp-iadc";
reg = <0x3600 0x100>;
#address-cells = <1>;
@@ -405,6 +412,7 @@
interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <16>;
qcom,adc-vdd-reference = <1800>;
+ qcom,iadc-vadc = <&pm8226_vadc>;
chan@0 {
label = "internal_rsense";
@@ -431,6 +439,7 @@
"low-thr-en-set";
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
+ qcom,adc_tm-vadc = <&pm8226_vadc>;
};
qcom,temp-alarm@2400 {
@@ -440,6 +449,7 @@
label = "pm8226_tz";
qcom,channel-num = <8>;
qcom,threshold-set = <0>;
+ qcom,temp_alarm-vadc = <&pm8226_vadc>;
};
qcom,pm8226_rtc {
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 2460377..12af463 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -39,6 +39,7 @@
label = "pm8941_tz";
qcom,channel-num = <8>;
qcom,threshold-set = <0>;
+ qcom,temp_alarm-vadc = <&pm8941_vadc>;
};
qcom,power-on@800 {
@@ -100,6 +101,7 @@
qcom,min-clock-period = <1000>;
qcom,max-clock-period = <160000>;
qcom,sample-rate = <4>;
+ qcom,bsi-vadc = <&pm8941_vadc>;
};
pm8941_coincell: qcom,coincell@2800 {
@@ -132,6 +134,9 @@
qcom,low-ocv-correction-limit-uv = <100>;
qcom,high-ocv-correction-limit-uv = <50>;
qcom,hold-soc-est = <3>;
+ qcom,bms-vadc = <&pm8941_vadc>;
+ qcom,bms-iadc = <&pm8941_iadc>;
+ qcom,bms-adc_tm = <&pm8941_adc_tm>;
qcom,bms-iadc@3800 {
reg = <0x3800 0x100>;
@@ -200,6 +205,8 @@
qcom,vbatdet-delta-mv = <100>;
qcom,resume-soc = <99>;
qcom,tchg-mins = <150>;
+ qcom,chg-vadc = <&pm8941_vadc>;
+ qcom,chg-adc_tm = <&pm8941_adc_tm>;
qcom,chgr@1000 {
status = "disabled";
@@ -806,6 +813,7 @@
interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <16>;
qcom,adc-vdd-reference = <1800>;
+ qcom,iadc-vadc = <&pm8941_vadc>;
chan@0 {
label = "internal_rsense";
@@ -832,6 +840,7 @@
"low-thr-en-set";
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
+ qcom,adc_tm-vadc = <&pm8941_vadc>;
/* Channel Node */
chan@b9 {
diff --git a/arch/arm/boot/dts/msm-pma8084.dtsi b/arch/arm/boot/dts/msm-pma8084.dtsi
index ecbfc53..808f0f6 100644
--- a/arch/arm/boot/dts/msm-pma8084.dtsi
+++ b/arch/arm/boot/dts/msm-pma8084.dtsi
@@ -77,6 +77,7 @@
interrupts = <0x0 0x24 0x0>;
label = "pma8084_tz";
qcom,threshold-set = <0>;
+ qcom,temp_alarm-vadc = <&pma8084_vadc>;
};
qcom,coincell@2800 {
@@ -322,6 +323,7 @@
"low-thr-en-set";
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
+ qcom,adc_tm-vadc = <&pma8084_vadc>;
};
qcom,rtc {
diff --git a/arch/arm/boot/dts/msm8226-cdp.dtsi b/arch/arm/boot/dts/msm8226-cdp.dtsi
index d94b41d..104cb4c 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-cdp.dtsi
@@ -319,7 +319,7 @@
qcom,ctrl-delay-us = <0>;
qcom,boost-curr-lim = <3>;
qcom,cp-sel = <0>;
- qcom,switch-freq = <2>;
+ qcom,switch-freq = <11>;
qcom,ovp-val = <0>;
qcom,num-strings = <1>;
qcom,id = <0>;
@@ -416,10 +416,6 @@
};
};
-&usb_otg_sw {
- status = "okay";
-};
-
&pm8226_vadc {
chan@14 {
label = "pa_therm0";
diff --git a/arch/arm/boot/dts/msm8226-iommu-domains.dtsi b/arch/arm/boot/dts/msm8226-iommu-domains.dtsi
index 25fca2a..769e4df 100644
--- a/arch/arm/boot/dts/msm8226-iommu-domains.dtsi
+++ b/arch/arm/boot/dts/msm8226-iommu-domains.dtsi
@@ -24,7 +24,8 @@
venus_domain_cp: qcom,iommu-domain2 {
label = "venus_cp";
qcom,iommu-contexts = <&venus_cp>;
- qcom,virtual-addr-pool = <0x1000000 0x3f000000>;
+ qcom,virtual-addr-pool = <0x1000000 0x1f800000
+ 0x20800000 0x1f800000>;
qcom,secure-domain;
};
};
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-mtp.dtsi
index 825e853..977c772 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-mtp.dtsi
@@ -127,7 +127,7 @@
interrupt-names = "core_irq", "async_irq", "pmic_id_irq";
qcom,hsusb-otg-mode = <3>;
- vbus_otg-supply = <&usb_otg_sw>;
+ vbus_otg-supply = <&pm8226_chg_otg>;
};
&sdcc1 {
@@ -327,7 +327,7 @@
qcom,ctrl-delay-us = <0>;
qcom,boost-curr-lim = <3>;
qcom,cp-sel = <0>;
- qcom,switch-freq = <2>;
+ qcom,switch-freq = <11>;
qcom,ovp-val = <0>;
qcom,num-strings = <1>;
qcom,id = <0>;
@@ -452,10 +452,6 @@
qcom,charging-disabled;
};
-&usb_otg_sw {
- status = "okay";
-};
-
&slim_msm {
tapan_codec {
qcom,cdc-micbias1-ext-cap;
diff --git a/arch/arm/boot/dts/msm8226-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
index 55d8691..a10b499 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -328,7 +328,7 @@
qcom,ctrl-delay-us = <0>;
qcom,boost-curr-lim = <3>;
qcom,cp-sel = <0>;
- qcom,switch-freq = <2>;
+ qcom,switch-freq = <11>;
qcom,ovp-val = <0>;
qcom,num-strings = <1>;
qcom,id = <0>;
@@ -442,3 +442,7 @@
qcom,fast-avg-setup = <0>;
};
};
+
+&android_usb {
+ qcom,android-usb-cdrom;
+};
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index d587b77..5b3da9b 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -482,14 +482,10 @@
regulator-name = "8226_smbbp_boost";
};
-&soc {
- usb_otg_sw: regulator-ncp380 {
- compatible = "regulator-fixed";
- regulator-name = "usb_otg_sw";
- gpio = <&msmgpio 67 0>;
- parent-supply = <&pm8226_chg_boost>;
- startup-delay-us = <4000>;
- enable-active-high;
- status = "disabled";
- };
+&pm8226_chg {
+ otg-parent-supply = <&pm8226_chg_boost>;
+};
+
+&pm8226_chg_otg {
+ regulator-name = "8226_smbbp_otg";
};
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-evt.dts b/arch/arm/boot/dts/msm8226-v2-qrd-evt.dts
index a2ad682..cb6c1af 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-evt.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-evt.dts
@@ -13,7 +13,6 @@
/dts-v1/;
/include/ "msm8226-v2.dtsi"
/include/ "msm8226-qrd.dtsi"
-/include/ "msm8226-camera-sensor-cdp.dtsi"
/include/ "dsi-panel-nt35590-720p-video.dtsi"
/ {
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index b836100..4b78238 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -182,11 +182,23 @@
<103000 134000>,
<268000 348000>,
<505000 657000>;
- qcom,iommu-groups = <&venus_domain_ns &venus_domain_cp>;
- qcom,iommu-group-buffer-types = <0xfff 0x1ff>;
qcom,buffer-type-tz-usage-table = <0x1 0x1>,
- <0x1fe 0x2>;
+ <0x2 0x2>,
+ <0x1f0 0x3>;
qcom,max-hw-load = <352800>; /* 720p @ 30 + 1080p @ 30 */
+ qcom,vidc-iommu-domains {
+ qcom,domain-ns {
+ qcom,vidc-domain-phandle = <&venus_domain_ns>;
+ qcom,vidc-partition-buffer-types = <0x1ff>,
+ <0x200>;
+ };
+
+ qcom,domain-cp {
+ qcom,vidc-domain-phandle = <&venus_domain_cp>;
+ qcom,vidc-partition-buffer-types = <0x2>,
+ <0x1f1>;
+ };
+ };
};
qcom,wfd {
@@ -275,10 +287,9 @@
<87 512 6000 6000>;
};
- android_usb@fe8050c8 {
+ android_usb: android_usb@fe8050c8 {
compatible = "qcom,android-usb";
reg = <0xfe8050c8 0xc8>;
- qcom,android-usb-cdrom;
qcom,android-usb-swfi-latency = <1>;
};
@@ -1072,16 +1083,17 @@
interrupts = <0 95 0>, <0 238 0>;
spi-max-frequency = <19200000>;
- gpios = <&msmgpio 3 0>, /* CLK */
- <&msmgpio 1 0>, /* MISO */
- <&msmgpio 0 0>; /* MOSI */
- cs-gpios = <&msmgpio 22 0>;
+ qcom,gpio-mosi = <&msmgpio 0 0>;
+ qcom,gpio-miso = <&msmgpio 1 0>;
+ qcom,gpio-clk = <&msmgpio 3 0>;
+ qcom,gpio-cs0 = <&msmgpio 22 0>;
qcom,infinite-mode = <0>;
qcom,use-bam;
qcom,ver-reg-exists;
qcom,bam-consumer-pipe-index = <12>;
qcom,bam-producer-pipe-index = <13>;
+ qcom,master-id = <86>;
};
qcom,bam_dmux@fc834000 {
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dts
index b0c0191..f3470c2 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dts
@@ -247,6 +247,8 @@
&sdhc_1 {
vdd-supply = <&pm8110_l17>;
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2900000 2900000>;
qcom,vdd-current-level = <200 400000>;
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dts
index 221ace4..0d4c174 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dts
@@ -285,6 +285,8 @@
&sdhc_1 {
vdd-supply = <&pm8110_l17>;
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2900000 2900000>;
qcom,vdd-current-level = <200 400000>;
diff --git a/arch/arm/boot/dts/msm8610-qrd.dtsi b/arch/arm/boot/dts/msm8610-qrd.dtsi
index ea47d45..bd1705f 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd.dtsi
@@ -237,6 +237,8 @@
&sdhc_1 {
vdd-supply = <&pm8110_l17>;
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2900000 2900000>;
qcom,vdd-current-level = <200 400000>;
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 0078861..00d0d15 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -173,13 +173,17 @@
qcom,vidc@fdc00000 {
compatible = "qcom,msm-vidc";
qcom,vidc-ns-map = <0x40000000 0x40000000>;
- qcom,iommu-groups = <&q6_domain_ns>;
- qcom,iommu-group-buffer-types = <0xfff>;
qcom,buffer-type-tz-usage-map = <0x1 0x1>,
<0x1fe 0x2>;
qcom,hfi = "q6";
qcom,max-hw-load = <108000>; /* 720p @ 30 * 1 */
- };
+ qcom,vidc-iommu-domains {
+ qcom,domain-ns {
+ qcom,vidc-domain-phandle = <&q6_domain_ns>;
+ qcom,vidc-partition-buffer-types = <0xfff>;
+ };
+ };
+};
qcom,usbbam@f9a44000 {
compatible = "qcom,usb-bam-msm";
@@ -254,6 +258,8 @@
interrupt-names = "core_irq", "bam_irq";
vdd-supply = <&pm8110_l17>;
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2900000 2900000>;
qcom,vdd-current-level = <9000 400000>;
@@ -518,16 +524,17 @@
interrupts = <0 98 0>, <0 238 0>;
spi-max-frequency = <50000000>;
- gpios = <&msmgpio 89 0>, /* CLK */
- <&msmgpio 87 0>, /* MISO */
- <&msmgpio 86 0>; /* MOSI */
- cs-gpios = <&msmgpio 88 0>;
+ qcom,gpio-mosi = <&msmgpio 86 0>;
+ qcom,gpio-miso = <&msmgpio 87 0>;
+ qcom,gpio-clk = <&msmgpio 89 0>;
+ qcom,gpio-cs0 = <&msmgpio 88 0>;
qcom,infinite-mode = <0>;
qcom,use-bam;
qcom,ver-reg-exists;
qcom,bam-consumer-pipe-index = <18>;
qcom,bam-producer-pipe-index = <19>;
+ qcom,master-id = <86>;
};
qcom,pronto@fb21b000 {
diff --git a/arch/arm/boot/dts/msm8926-qrd.dts b/arch/arm/boot/dts/msm8926-qrd.dts
index 8497ba2..e056b7e 100644
--- a/arch/arm/boot/dts/msm8926-qrd.dts
+++ b/arch/arm/boot/dts/msm8926-qrd.dts
@@ -13,7 +13,6 @@
/dts-v1/;
/include/ "msm8926.dtsi"
/include/ "msm8226-qrd.dtsi"
-/include/ "msm8226-camera-sensor-cdp.dtsi"
/ {
model = "Qualcomm MSM 8926 QRD";
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index 4be2b38..1413e0c 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -94,12 +94,13 @@
qcom,ispif@fda0A000 {
cell-index = <0>;
- compatible = "qcom,ispif";
+ compatible = "qcom,ispif-v3.0", "qcom,ispif";
reg = <0xfda0A000 0x500>,
<0xfda00020 0x10>;
reg-names = "ispif", "csi_clk_mux";
interrupts = <0 55 0>;
interrupt-names = "ispif";
+ qcom,num-isps = <0x2>;
};
qcom,vfe@fda10000 {
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index e66ea25..fa57244 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -234,6 +234,7 @@
hsic,ignore-cal-pad-config;
hsic,strobe-pad-offset = <0x2050>;
hsic,data-pad-offset = <0x2054>;
+ qcom,phy-susp-sof-workaround;
qcom,msm-bus,name = "hsic";
qcom,msm-bus,num-cases = <2>;
@@ -272,7 +273,7 @@
qcom,ctrl-delay-us = <0>;
qcom,boost-curr-lim = <3>;
qcom,cp-sel = <0>;
- qcom,switch-freq = <2>;
+ qcom,switch-freq = <11>;
qcom,ovp-val = <2>;
qcom,num-strings = <1>;
qcom,id = <0>;
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index 7f714e8..3d20f7c 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -271,7 +271,7 @@
qcom,ctrl-delay-us = <0>;
qcom,boost-curr-lim = <3>;
qcom,cp-sel = <0>;
- qcom,switch-freq = <2>;
+ qcom,switch-freq = <11>;
qcom,ovp-val = <2>;
qcom,num-strings = <1>;
qcom,id = <0>;
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 51cb226..f90599a 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -403,6 +403,7 @@
hsic,ignore-cal-pad-config;
hsic,strobe-pad-offset = <0x2050>;
hsic,data-pad-offset = <0x2054>;
+ qcom,phy-susp-sof-workaround;
qcom,msm-bus,name = "hsic";
qcom,msm-bus,num-cases = <2>;
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index 4ee56ad..c1a8792 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -212,7 +212,7 @@
qcom,ctrl-delay-us = <0>;
qcom,boost-curr-lim = <3>;
qcom,cp-sel = <0>;
- qcom,switch-freq = <2>;
+ qcom,switch-freq = <11>;
qcom,ovp-val = <2>;
qcom,num-strings = <1>;
qcom,id = <0>;
diff --git a/arch/arm/boot/dts/msm8974-rumi.dtsi b/arch/arm/boot/dts/msm8974-rumi.dtsi
index c01a4e5..152ac4d 100644
--- a/arch/arm/boot/dts/msm8974-rumi.dtsi
+++ b/arch/arm/boot/dts/msm8974-rumi.dtsi
@@ -13,6 +13,12 @@
/include/ "msm8974-leds.dtsi"
/include/ "msm8974-camera-sensor-cdp.dtsi"
+/ {
+ aliases {
+ spi0 = &spi_0;
+ };
+};
+
&soc {
timer {
clock-frequency = <5000000>;
@@ -42,17 +48,28 @@
status = "disable";
};
- spi@f9923000 {
+ spi_0: spi@f9923000 { /* BLSP1 QUP1 */
compatible = "qcom,spi-qup-v2";
- reg = <0xf9923000 0x1000>;
- interrupts = <0 95 0>;
- spi-max-frequency = <24000000>;
#address-cells = <1>;
#size-cells = <0>;
- gpios = <&msmgpio 3 0>, /* CLK */
- <&msmgpio 1 0>, /* MISO */
- <&msmgpio 0 0>; /* MOSI */
- cs-gpios = <&msmgpio 9 0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0xf9923000 0x1000>,
+ <0xf9904000 0xf000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 95 0>, <0 238 0>;
+ spi-max-frequency = <19200000>;
+
+ qcom,gpio-mosi = <&msmgpio 0 0>;
+ qcom,gpio-miso = <&msmgpio 1 0>;
+ qcom,gpio-clk = <&msmgpio 3 0>;
+ qcom,gpio-cs0 = <&msmgpio 9 0>;
+
+ qcom,infinite-mode = <0>;
+ qcom,use-bam;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <12>;
+ qcom,bam-producer-pipe-index = <13>;
+ qcom,master-id = <86>;
ethernet-switch@2 {
compatible = "simtec,ks8851";
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 0b3b60f..9d5e50b 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -136,12 +136,29 @@
<3240000 1600000>,
<4048000 1600000>,
<4264000 1600000>;
- qcom,iommu-groups = <&venus_domain_ns &venus_domain_sec_bitstream
- &venus_domain_sec_pixel &venus_domain_sec_non_pixel>;
- qcom,iommu-group-buffer-types = <0xfff 0x91 0x42 0x120>;
qcom,buffer-type-tz-usage-table = <0x91 0x1>,
<0x42 0x2>,
<0x120 0x3>;
+ qcom,vidc-iommu-domains {
+ qcom,domain-ns {
+ qcom,vidc-domain-phandle = <&venus_domain_ns>;
+ qcom,vidc-partition-buffer-types = <0x1ff>,
+ <0x200>;
+ };
+ qcom,domain-sec-bs {
+ qcom,vidc-domain-phandle = <&venus_domain_sec_bitstream>;
+ qcom,vidc-partition-buffer-types = <0x91>;
+ };
+ qcom,domain-sec-px {
+ qcom,vidc-domain-phandle = <&venus_domain_sec_pixel>;
+ qcom,vidc-partition-buffer-types = <0x42>;
+ };
+ qcom,domain-sec-np {
+ qcom,vidc-domain-phandle = <&venus_domain_sec_non_pixel>;
+ qcom,vidc-partition-buffer-types = <0x120>;
+ };
+ };
+
};
&krait_pdn {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 4360fe0..c8e3d96 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -580,18 +580,28 @@
qcom,bam-dma-res-pipes = <6>;
};
- spi_7: spi_epm: spi@f9966000 {
+ spi_7: spi_epm: spi@f9966000 { /* BLSP2 QUP4 */
compatible = "qcom,spi-qup-v2";
- reg = <0xf9966000 0x1000>;
- interrupts = <0 104 0>;
- spi-max-frequency = <19200000>;
#address-cells = <1>;
#size-cells = <0>;
- qcom,master-id = <84>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0xf9966000 0x1000>,
+ <0xf9944000 0x15000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 104 0>, <0 239 0>;
+ spi-max-frequency = <19200000>;
+
qcom,gpio-mosi = <&msmgpio 53 0>;
qcom,gpio-miso = <&msmgpio 54 0>;
qcom,gpio-clk = <&msmgpio 56 0>;
qcom,gpio-cs0 = <&msmgpio 55 0>;
+
+ qcom,infinite-mode = <0>;
+ qcom,use-bam;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <18>;
+ qcom,bam-producer-pipe-index = <19>;
+ qcom,master-id = <84>;
};
tspp: msm_tspp@f99d8000 {
@@ -816,18 +826,28 @@
qcom,master-id = <86>;
};
- spi_0: spi@f9923000 {
+ spi_0: spi@f9923000 { /* BLSP1 QUP1 */
compatible = "qcom,spi-qup-v2";
- reg = <0xf9923000 0x1000>;
- interrupts = <0 95 0>;
- spi-max-frequency = <19200000>;
#address-cells = <1>;
#size-cells = <0>;
- qcom,master-id = <86>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0xf9923000 0x1000>,
+ <0xf9904000 0xf000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 95 0>, <0 238 0>;
+ spi-max-frequency = <19200000>;
+
qcom,gpio-mosi = <&msmgpio 0 0>;
qcom,gpio-miso = <&msmgpio 1 0>;
qcom,gpio-clk = <&msmgpio 3 0>;
- qcom,gpio-cs2 = <&msmgpio 9 0>;
+ qcom,gpio-cs0 = <&msmgpio 9 0>;
+
+ qcom,infinite-mode = <0>;
+ qcom,use-bam;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <12>;
+ qcom,bam-producer-pipe-index = <13>;
+ qcom,master-id = <86>;
};
qcom,acpuclk@f9000000 {
@@ -877,6 +897,7 @@
qcom,vdd-voltage-level = <1 5 7>;
qcom,dwc-hsphy-init = <0x00D191A4>;
qcom,misc-ref = <&pm8941_misc>;
+ dwc_usb3-adc_tm = <&pm8941_adc_tm>;
qcom,msm-bus,name = "usb3";
qcom,msm-bus,num-cases = <2>;
diff --git a/arch/arm/boot/dts/msm8974pro-ac-mtp.dts b/arch/arm/boot/dts/msm8974pro-ac-mtp.dts
index b8df576..9ac9aaf 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-mtp.dts
@@ -27,3 +27,103 @@
&sdhc_1 {
qcom,clk-rates = <400000 20000000 25000000 50000000 100000000>;
};
+
+&pma8084_vadc {
+ chan@73 {
+ label = "msm_therm";
+ reg = <0x73>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@75 {
+ label = "pa_therm0";
+ reg = <0x75>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@77 {
+ label = "pa_therm1";
+ reg = <0x77>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@78 {
+ label = "quiet_therm";
+ reg = <0x78>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+};
+
+&pma8084_adc_tm {
+ chan@73 {
+ label = "msm_therm";
+ reg = <0x73>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x48>;
+ qcom,thermal-node;
+ };
+
+ chan@75 {
+ label = "pa_therm0";
+ reg = <0x75>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x68>;
+ qcom,thermal-node;
+ };
+
+ chan@77 {
+ label = "pa_therm1";
+ reg = <0x77>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x70>;
+ qcom,thermal-node;
+ };
+
+ chan@78 {
+ label = "quiet_therm";
+ reg = <0x78>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x78>;
+ qcom,thermal-node;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi
index 4d10ded..0989c34 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi
@@ -21,14 +21,6 @@
};
/include/ "msm-pm8941.dtsi"
-&pma8084_vadc {
- status = "disabled";
-};
-
-&pma8084_adc_tm {
- status = "disabled";
-};
-
&pm8941_lsid0 {
qcom,power-on@800 {
status = "disabled";
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 59d7ba0..0e7baf1 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -328,18 +328,26 @@
interrupt-names = "bam_irq";
};
- spi_0: spi@f9924000 {
+ spi_0: spi@f9924000 { /* BLSP1 QUP2 */
compatible = "qcom,spi-qup-v2";
- reg = <0xf9924000 0x1000>;
- interrupts = <0 96 0>;
- spi-max-frequency = <25000000>;
#address-cells = <1>;
#size-cells = <0>;
- gpios = <&msmgpio 7 0>, /* CLK */
- <&msmgpio 5 0>, /* MISO */
- <&msmgpio 4 0>; /* MOSI */
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0xf9924000 0x1000>,
+ <0xf9904000 0x11000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 96 0>, <0 238 0>;
+ spi-max-frequency = <19200000>;
+ qcom,gpio-mosi = <&msmgpio 4 0>;
+ qcom,gpio-miso = <&msmgpio 5 0>;
+ qcom,gpio-clk = <&msmgpio 7 0>;
+ qcom,gpio-cs0 = <&msmgpio 6 0>;
- cs-gpios = <&msmgpio 6 0>;
+ qcom,infinite-mode = <0>;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <14>;
+ qcom,bam-producer-pipe-index = <15>;
+ qcom,master-id = <86>;
ethernet-switch@0 {
compatible = "simtec,ks8851";
@@ -736,7 +744,23 @@
compatible = "qcom,msm-dai-q6-dev";
qcom,msm-dai-q6-dev-id = <240>;
};
+
+ qcom,msm-dai-q6-incall-record-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32771>;
+ };
+
+ qcom,msm-dai-q6-incall-record-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32772>;
+ };
+
+ qcom,msm-dai-q6-incall-music-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32773>;
+ };
};
+
qcom,msm-pcm-dtmf {
compatible = "qcom,msm-pcm-dtmf";
};
diff --git a/arch/arm/boot/dts/msmkrypton.dtsi b/arch/arm/boot/dts/msmkrypton.dtsi
index cdaf964..f3e9dbb 100644
--- a/arch/arm/boot/dts/msmkrypton.dtsi
+++ b/arch/arm/boot/dts/msmkrypton.dtsi
@@ -17,6 +17,10 @@
compatible = "qcom,msmkrypton";
interrupt-parent = <&intc>;
+ aliases {
+ spi6 = &spi_6;
+ };
+
soc: soc { };
};
@@ -140,18 +144,27 @@
};
spi_6: spi@f9928000 { /* BLSP1 QUP6 */
- cell-index = <0>;
compatible = "qcom,spi-qup-v2";
#address-cells = <1>;
#size-cells = <0>;
- reg = <0xf9928000 0x1000>;
- interrupts = <0 100 0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0xf9928000 0x1000>,
+ <0xf9904000 0x19000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 100 0>, <0 238 0>;
spi-max-frequency = <19200000>;
- gpios = <&msmgpio 23 0>, /* CLK */
- <&msmgpio 21 0>, /* MISO */
- <&msmgpio 20 0>; /* MOSI */
- cs-gpios = <&msmgpio 22 0>;
+ qcom,gpio-mosi = <&msmgpio 20 0>;
+ qcom,gpio-miso = <&msmgpio 21 0>;
+ qcom,gpio-clk = <&msmgpio 23 0>;
+ qcom,gpio-cs0 = <&msmgpio 22 0>;
+
+ qcom,infinite-mode = <0>;
+ qcom,use-bam;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <22>;
+ qcom,bam-producer-pipe-index = <23>;
+ qcom,master-id = <86>;
};
qcom,ipc-spinlock@fd484000 {
diff --git a/arch/arm/boot/dts/msmsamarium.dtsi b/arch/arm/boot/dts/msmsamarium.dtsi
index 251bef2..d76c2c1 100644
--- a/arch/arm/boot/dts/msmsamarium.dtsi
+++ b/arch/arm/boot/dts/msmsamarium.dtsi
@@ -42,7 +42,7 @@
interrupt-controller;
#interrupt-cells = <2>;
reg = <0xfd510000 0x4000>;
- ngpio = <145>;
+ ngpio = <146>;
interrupts = <0 208 0>;
qcom,direct-connect-irqs = <8>;
};
@@ -89,6 +89,14 @@
status = "disabled";
};
+ qcom,sps@f9980000 {
+ compatible = "qcom,msm_sps";
+ reg = <0xf9984000 0x15000>,
+ <0xf9999000 0xb000>;
+ reg-names = "bam_mem", "core_mem";
+ interrupts = <0 94 0>;
+ };
+
qcom,wdt@f9017000 {
compatible = "qcom,msm-watchdog";
reg = <0xf9017000 0x1000>;
@@ -234,4 +242,18 @@
cell-index = <0>;
qcom,not-wakeup; /* Needed until MPM is fully configured. */
};
+
+ tsens: tsens@fc4a8000 {
+ compatible = "qcom,msm-tsens";
+ reg = <0xfc4a8000 0x2000>,
+ <0xfc4bc000 0x1000>;
+ reg-names = "tsens_physical", "tsens_eeprom_physical";
+ interrupts = <0 184 0>;
+ qcom,sensors = <11>;
+ qcom,slope = <3200 3200 3200 3200 3200 3200 3200 3200 3200
+ 3200 3200>;
+ qcom,calib-mode = "fuse_map1";
+ };
};
+
+/include/ "msm-pma8084.dtsi"
diff --git a/arch/arm/kernel/sched_clock.c b/arch/arm/kernel/sched_clock.c
index ad9dfb2..bb97140 100644
--- a/arch/arm/kernel/sched_clock.c
+++ b/arch/arm/kernel/sched_clock.c
@@ -68,7 +68,9 @@
smp_rmb();
} while (epoch_cyc != cd.epoch_cyc_copy);
- return epoch_ns + cyc_to_ns((cyc - epoch_cyc) & mask, cd.mult, cd.shift);
+ cyc = read_sched_clock();
+ cyc = (cyc - epoch_cyc) & sched_clock_mask;
+ return epoch_ns + cyc_to_ns(cyc, cd.mult, cd.shift);
}
/*
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 76bd74c..5c0d2cf 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -522,6 +522,7 @@
select ARM_GIC
select CPU_V7
select MSM_SCM
+ select MSM_PIL
select MSM_GPIOMUX
select MULTI_IRQ_HANDLER
select MSM_SPM_V2
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 72472f9..9296515 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -60,6 +60,18 @@
dtb-$(CONFIG_ARCH_MSM8974) += apq8074-v2.0-1-cdp.dtb
dtb-$(CONFIG_ARCH_MSM8974) += apq8074-v2.0-1-liquid.dtb
dtb-$(CONFIG_ARCH_MSM8974) += apq8074-v2.0-1-dragonboard.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += apq8074-v2.2-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += apq8074-v2.2-liquid.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += apq8074-v2.2-dragonboard.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v2.2-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v2.2-fluid.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v2.2-liquid.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v2.2-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ab-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ab-fluid.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ab-liquid.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ab-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ac-mtp.dtb
# APQ8084
zreladdr-$(CONFIG_ARCH_APQ8084) := 0x00008000
@@ -85,6 +97,7 @@
# MSM8226
zreladdr-$(CONFIG_ARCH_MSM8226) := 0x00008000
dtb-$(CONFIG_ARCH_MSM8226) += msm8226-sim.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-fluid.dtb
dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-cdp.dtb
dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-mtp.dtb
dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-qrd-evt.dtb
@@ -120,6 +133,8 @@
# MSM8610
zreladdr-$(CONFIG_ARCH_MSM8610) := 0x00008000
+ dtb-$(CONFIG_ARCH_MSM8610) += msm8610-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8610) += msm8610-mtp.dtb
dtb-$(CONFIG_ARCH_MSM8610) += msm8610-rumi.dtb
dtb-$(CONFIG_ARCH_MSM8610) += msm8610-sim.dtb
dtb-$(CONFIG_ARCH_MSM8610) += msm8610-qrd-skuaa.dtb
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 21a940d..1460f94 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -233,6 +233,7 @@
#define UL_TIMEOUT_DELAY 1000 /* in ms */
#define ENABLE_DISCONNECT_ACK 0x1
#define SHUTDOWN_TIMEOUT_MS 500
+#define UL_WAKEUP_TIMEOUT_MS 2000
static void toggle_apps_ack(void);
static void reconnect_to_bam(void);
static void disconnect_to_bam(void);
@@ -1663,7 +1664,8 @@
if (wait_for_ack) {
BAM_DMUX_LOG("%s waiting for previous ack\n", __func__);
ret = wait_for_completion_timeout(
- &ul_wakeup_ack_completion, HZ);
+ &ul_wakeup_ack_completion,
+ msecs_to_jiffies(UL_WAKEUP_TIMEOUT_MS));
wait_for_ack = 0;
if (unlikely(ret == 0) && ssrestart_check()) {
mutex_unlock(&wakeup_lock);
@@ -1674,14 +1676,16 @@
INIT_COMPLETION(ul_wakeup_ack_completion);
power_vote(1);
BAM_DMUX_LOG("%s waiting for wakeup ack\n", __func__);
- ret = wait_for_completion_timeout(&ul_wakeup_ack_completion, HZ);
+ ret = wait_for_completion_timeout(&ul_wakeup_ack_completion,
+ msecs_to_jiffies(UL_WAKEUP_TIMEOUT_MS));
if (unlikely(ret == 0) && ssrestart_check()) {
mutex_unlock(&wakeup_lock);
BAM_DMUX_LOG("%s timeout wakeup ack\n", __func__);
return;
}
BAM_DMUX_LOG("%s waiting completion\n", __func__);
- ret = wait_for_completion_timeout(&bam_connection_completion, HZ);
+ ret = wait_for_completion_timeout(&bam_connection_completion,
+ msecs_to_jiffies(UL_WAKEUP_TIMEOUT_MS));
if (unlikely(ret == 0) && ssrestart_check()) {
mutex_unlock(&wakeup_lock);
BAM_DMUX_LOG("%s timeout power on\n", __func__);
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index a93cfe5..a29bb88 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -630,16 +630,27 @@
static struct rpm_regulator_init_data *rpm_data;
int i;
- if (machine_is_msm8960_cdp()) {
+ if (machine_is_msm8960_cdp() || cpu_is_msm8960ab()) {
/* Only modify LVS6 consumers for CDP targets. */
for (i = 0; i < ARRAY_SIZE(msm_rpm_regulator_init_data); i++) {
rpm_data = &msm_rpm_regulator_init_data[i];
- if (rpm_data->id == RPM_VREG_ID_PM8921_LVS6) {
+ if (machine_is_msm8960_cdp() &&
+ rpm_data->id == RPM_VREG_ID_PM8921_LVS6) {
rpm_data->init_data.consumer_supplies
= vreg_consumers_CDP_LVS6;
rpm_data->init_data.num_consumer_supplies
= ARRAY_SIZE(vreg_consumers_CDP_LVS6);
}
+ if (cpu_is_msm8960ab() &&
+ rpm_data->id == RPM_VREG_ID_PM8921_S7) {
+ rpm_data->init_data.constraints.min_uV =
+ 1275000;
+ rpm_data->init_data.constraints.max_uV =
+ 1275000;
+ rpm_data->init_data.constraints.input_uV =
+ 1275000;
+ rpm_data->default_uV = 1275000;
+ }
}
}
}
diff --git a/arch/arm/mach-msm/board-fsm9900-gpiomux.c b/arch/arm/mach-msm/board-fsm9900-gpiomux.c
index dede706..990aefc 100644
--- a/arch/arm/mach-msm/board-fsm9900-gpiomux.c
+++ b/arch/arm/mach-msm/board-fsm9900-gpiomux.c
@@ -17,6 +17,370 @@
#include <mach/board.h>
#include <mach/gpiomux.h>
+static struct gpiomux_setting blsp_uart_no_pull_config = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting blsp_uart_pull_up_config = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting blsp_i2c_config = {
+ .func = GPIOMUX_FUNC_3,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config fsm_blsp_configs[] __initdata = {
+ {
+ .gpio = 0, /* BLSP UART1 TX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &blsp_uart_no_pull_config,
+ },
+ },
+ {
+ .gpio = 1, /* BLSP UART1 RX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &blsp_uart_pull_up_config,
+ },
+ },
+ {
+ .gpio = 2, /* BLSP I2C SDA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &blsp_i2c_config,
+ },
+ },
+ {
+ .gpio = 3, /* BLSP I2C SCL */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &blsp_i2c_config,
+ },
+ },
+ {
+ .gpio = 6, /* BLSP I2C SDA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &blsp_i2c_config,
+ },
+ },
+ {
+ .gpio = 7, /* BLSP I2C SCL */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &blsp_i2c_config,
+ },
+ },
+ {
+ .gpio = 36, /* BLSP UART10 TX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &blsp_uart_no_pull_config,
+ },
+ },
+ {
+ .gpio = 37, /* BLSP UART10 RX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &blsp_uart_pull_up_config,
+ },
+ },
+ {
+ .gpio = 38, /* BLSP I2C10 SDA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &blsp_i2c_config,
+ },
+ },
+ {
+ .gpio = 39, /* BLSP I2C10 SCL */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &blsp_i2c_config,
+ },
+ },
+
+};
+
+static struct gpiomux_setting geni_func4_config = {
+ .func = GPIOMUX_FUNC_4,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting geni_func5_config = {
+ .func = GPIOMUX_FUNC_5,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config fsm_geni_configs[] __initdata = {
+ {
+ .gpio = 8, /* GENI7 DATA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &geni_func4_config,
+ },
+ },
+ {
+ .gpio = 9, /* GENI1 DATA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &geni_func4_config,
+ },
+ },
+ {
+ .gpio = 10, /* GENI2 DATA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &geni_func4_config,
+ },
+ },
+ {
+ .gpio = 11, /* GENI7 CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &geni_func4_config,
+ },
+ },
+ {
+ .gpio = 20, /* GENI3 DATA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &geni_func5_config,
+ },
+ },
+ {
+ .gpio = 21, /* GENI4 DATA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &geni_func5_config,
+ },
+ },
+ {
+ .gpio = 22, /* GENI6 DATA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &geni_func5_config,
+ },
+ },
+ {
+ .gpio = 23, /* GENI6 CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &geni_func5_config,
+ },
+ },
+ {
+ .gpio = 30, /* GENI5 DATA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &geni_func4_config,
+ },
+ },
+ {
+ .gpio = 31, /* GENI5 CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &geni_func4_config,
+ },
+ },
+
+};
+
+static struct gpiomux_setting dan_spi_func4_config = {
+ .func = GPIOMUX_FUNC_4,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting dan_spi_func1_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config fsm_dan_spi_configs[] __initdata = {
+ {
+ .gpio = 12, /* BLSP DAN0 SPI_MOSI */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &dan_spi_func4_config,
+ },
+ },
+ {
+ .gpio = 13, /* BLSP DAN0 SPI_MISO */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &dan_spi_func4_config,
+ },
+ },
+ {
+ .gpio = 14, /* BLSP DAN0 SPI_CS */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &dan_spi_func4_config,
+ },
+ },
+ {
+ .gpio = 15, /* BLSP DAN0 SPI_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &dan_spi_func4_config,
+ },
+ },
+ {
+ .gpio = 16, /* BLSP DAN1 SPI_MOSI */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &dan_spi_func4_config,
+ },
+ },
+ {
+ .gpio = 17, /* BLSP DAN1 SPI_MISO */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &dan_spi_func4_config,
+ },
+ },
+ {
+ .gpio = 18, /* BLSP DAN1 SPI_CS */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &dan_spi_func4_config,
+ },
+ },
+ {
+ .gpio = 19, /* BLSP DAN1 SPI_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &dan_spi_func4_config,
+ },
+ },
+ {
+ .gpio = 81, /* BLSP DAN1 SPI_CS0 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &dan_spi_func1_config,
+ },
+ },
+ {
+ .gpio = 82, /* BLSP DAN1 SPI_CS1 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &dan_spi_func1_config,
+ },
+ },
+};
+
+static struct gpiomux_setting uim_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_4MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config fsm_uim_configs[] __initdata = {
+ {
+ .gpio = 24, /* UIM_DATA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &uim_config,
+ },
+ },
+ {
+ .gpio = 25, /* UIM_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &uim_config,
+ },
+ },
+ {
+ .gpio = 26, /* UIM_RESET */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &uim_config,
+ },
+ },
+ {
+ .gpio = 27, /* UIM_PRESENT */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &uim_config,
+ },
+ },
+};
+
+static struct gpiomux_setting pcie_config = {
+ .func = GPIOMUX_FUNC_4,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config fsm_pcie_configs[] __initdata = {
+ {
+ .gpio = 28, /* BLSP PCIE1_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &pcie_config,
+ },
+ },
+ {
+ .gpio = 32, /* BLSP PCIE0_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &pcie_config,
+ },
+ },
+};
+
+static struct gpiomux_setting pps_out_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_4MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting pps_in_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting gps_clk_in_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting gps_nav_tlmm_blank_config = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+static struct msm_gpiomux_config fsm_gps_configs[] __initdata = {
+ {
+ .gpio = 40, /* GPS_PPS_OUT */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &pps_out_config,
+ },
+ },
+ {
+ .gpio = 41, /* GPS_PPS_IN */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &pps_in_config,
+ },
+ },
+ {
+ .gpio = 43, /* GPS_CLK_IN */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gps_clk_in_config,
+ },
+ },
+ {
+ .gpio = 120, /* GPS_NAV_TLMM_BLANK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gps_nav_tlmm_blank_config,
+ },
+ },
+};
+
+static struct gpiomux_setting sd_detect_config = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting sd_wp_config = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config fsm_sd_configs[] __initdata = {
+ {
+ .gpio = 42, /* SD_CARD_DET */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &sd_detect_config,
+ },
+ },
+ {
+ .gpio = 122, /* BLSP SD WRITE PROTECT */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &sd_wp_config,
+ },
+ },
+};
+
void __init fsm9900_init_gpiomux(void)
{
int rc;
@@ -26,4 +390,13 @@
pr_err("%s failed %d\n", __func__, rc);
return;
}
+
+ msm_gpiomux_install(fsm_blsp_configs, ARRAY_SIZE(fsm_blsp_configs));
+ msm_gpiomux_install(fsm_geni_configs, ARRAY_SIZE(fsm_geni_configs));
+ msm_gpiomux_install(fsm_dan_spi_configs,
+ ARRAY_SIZE(fsm_dan_spi_configs));
+ msm_gpiomux_install(fsm_uim_configs, ARRAY_SIZE(fsm_uim_configs));
+ msm_gpiomux_install(fsm_pcie_configs, ARRAY_SIZE(fsm_pcie_configs));
+ msm_gpiomux_install(fsm_gps_configs, ARRAY_SIZE(fsm_gps_configs));
+ msm_gpiomux_install(fsm_sd_configs, ARRAY_SIZE(fsm_sd_configs));
}
diff --git a/arch/arm/mach-msm/board-samarium.c b/arch/arm/mach-msm/board-samarium.c
index 6133983..9f865a9 100644
--- a/arch/arm/mach-msm/board-samarium.c
+++ b/arch/arm/mach-msm/board-samarium.c
@@ -16,6 +16,7 @@
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/memory.h>
+#include <linux/msm_tsens.h>
#include <asm/hardware/gic.h>
#include <asm/mach/map.h>
#include <asm/mach/arch.h>
@@ -109,6 +110,7 @@
msm_init_modem_notifier_list();
msm_smd_init();
msm_clock_init(&msm_dummy_clock_init_data);
+ tsens_tm_init_driver();
}
static void __init msmsamarium_map_io(void)
diff --git a/arch/arm/mach-msm/clock-8084.c b/arch/arm/mach-msm/clock-8084.c
index ffd33a8..fd1714c 100644
--- a/arch/arm/mach-msm/clock-8084.c
+++ b/arch/arm/mach-msm/clock-8084.c
@@ -444,6 +444,9 @@
CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc342000.cti", OFF),
CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc343000.cti", OFF),
CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc344000.cti", OFF),
+
+ CLK_DUMMY("iface_clk", gcc_prng_ahb_clk.c,
+ "f9bff000.qcom,msm-rng", OFF),
};
struct clock_init_data msm8084_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/clock-8092.c b/arch/arm/mach-msm/clock-8092.c
index ec7a4b0..802cd1b 100644
--- a/arch/arm/mach-msm/clock-8092.c
+++ b/arch/arm/mach-msm/clock-8092.c
@@ -304,6 +304,9 @@
CLK_DUMMY("core_clk", NULL, "fdc84000.qcom,iommu", OFF),
CLK_DUMMY("iface_clk", NULL, "fdee4000.qcom,iommu", OFF),
CLK_DUMMY("core_clk", NULL, "fdee4000.qcom,iommu", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fdfb6000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fdfb6000.qcom,iommu", OFF),
+ CLK_DUMMY("alt_core_clk", NULL, "fdfb6000.qcom,iommu", OFF),
/* BCSS broadcast */
CLK_DUMMY("", bcc_dem_core_b_clk_src.c, "", OFF),
CLK_DUMMY("", adc_01_clk_src.c, "", OFF),
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 0cd5d55..383af54 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -3251,6 +3251,7 @@
CLK_LOOKUP("xo", cxo_otg_clk.c, "f9a55000.usb"),
CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c, "f9a55000.usb"),
CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c, "f9a55000.usb"),
+ CLK_LOOKUP("sleep_clk", gcc_usb2a_phy_sleep_clk.c, "f9a55000.usb"),
/* SPS CLOCKS */
CLK_LOOKUP("dfab_clk", pnoc_sps_clk.c, "f9984000.qcom,sps"),
@@ -3309,10 +3310,6 @@
CLK_LOOKUP("iface_clk", gcc_sdcc3_ahb_clk.c, "msm_sdcc.3"),
CLK_LOOKUP("core_clk", gcc_sdcc3_apps_clk.c, "msm_sdcc.3"),
- CLK_LOOKUP("sleep_a_clk", gcc_usb2a_phy_sleep_clk.c, "msm_dwc3"),
- CLK_LOOKUP("ref_clk", diff_clk.c, "msm_dwc3"),
-
-
CLK_LOOKUP("bus_clk", pnoc_clk.c, ""),
CLK_LOOKUP("bus_clk", pnoc_a_clk.c, ""),
CLK_LOOKUP("bus_clk", snoc_clk.c, ""),
@@ -3616,6 +3613,13 @@
*/
clk_prepare_enable(&xo_a_clk.c);
+ /*
+ * Handoff will override the prepare enable count as well as the rate
+ * Set them again.
+ */
+ clk_set_rate(&mmssnoc_ahb_a_clk.c, 40000000);
+ clk_prepare_enable(&mmssnoc_ahb_a_clk.c);
+
/* Set an initial rate (fmax at nominal) on the MMSSNOC AXI clock */
clk_set_rate(&axi_clk_src.c, 200000000);
@@ -3693,6 +3697,9 @@
if (IS_ERR(vdd_sr2_pll.regulator[1]))
panic("clock-8226: Unable to get the vdd_sr2_dig regulator!");
+
+ enable_rpm_scaling();
+
/*
* Hold an active set vote at a rate of 40MHz for the MMSS NOC AHB
* source. Sleep set vote is 0.
@@ -3700,8 +3707,7 @@
* access mmss clock controller registers.
*/
clk_set_rate(&mmssnoc_ahb_a_clk.c, 40000000);
-
- enable_rpm_scaling();
+ clk_prepare_enable(&mmssnoc_ahb_a_clk.c);
reg_init();
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index b1b9397..4fb3f43 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -2749,7 +2749,7 @@
};
static struct clk_lookup msm_clocks_8610[] = {
- CLK_LOOKUP("xo", cxo_otg_clk.c, "msm_otg"),
+ CLK_LOOKUP("xo", cxo_otg_clk.c, "f9a55000.usb"),
CLK_LOOKUP("xo", cxo_lpass_pil_clk.c, "fe200000.qcom,lpass"),
CLK_LOOKUP("xo", cxo_lpm_clk.c, "fc4281d0.qcom,mpm"),
@@ -2924,7 +2924,7 @@
CLK_LOOKUP("core_clk", gcc_sdcc1_apps_clk.c, "msm_sdcc.1"),
CLK_LOOKUP("iface_clk", gcc_sdcc2_ahb_clk.c, "msm_sdcc.2"),
CLK_LOOKUP("core_clk", gcc_sdcc2_apps_clk.c, "msm_sdcc.2"),
- CLK_LOOKUP("core_clk", gcc_usb2a_phy_sleep_clk.c, ""),
+ CLK_LOOKUP("sleep_clk", gcc_usb2a_phy_sleep_clk.c, "f9a55000.usb"),
CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c, "f9a55000.usb"),
CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c, "f9a55000.usb"),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index a8cb46e..cd6d582 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -718,17 +718,38 @@
DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(cxo_a1_pin, cxo_a1_a_pin, A1_ID);
DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(cxo_a2_pin, cxo_a2_a_pin, A2_ID);
+static unsigned int soft_vote_gpll0;
+
+static struct pll_vote_clk gpll0_ao_clk_src = {
+ .en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE_REG,
+ .en_mask = BIT(0),
+ .status_reg = (void __iomem *)GPLL0_STATUS_REG,
+ .status_mask = BIT(17),
+ .soft_vote = &soft_vote_gpll0,
+ .soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .parent = &cxo_a_clk_src.c,
+ .rate = 600000000,
+ .dbg_name = "gpll0_ao_clk_src",
+ .ops = &clk_ops_pll_acpu_vote,
+ CLK_INIT(gpll0_ao_clk_src.c),
+ },
+};
+
static struct pll_vote_clk gpll0_clk_src = {
.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE_REG,
.en_mask = BIT(0),
.status_reg = (void __iomem *)GPLL0_STATUS_REG,
.status_mask = BIT(17),
+ .soft_vote = &soft_vote_gpll0,
+ .soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
.base = &virt_bases[GCC_BASE],
.c = {
.parent = &cxo_clk_src.c,
.rate = 600000000,
.dbg_name = "gpll0_clk_src",
- .ops = &clk_ops_pll_vote,
+ .ops = &clk_ops_pll_acpu_vote,
CLK_INIT(gpll0_clk_src.c),
},
};
@@ -4895,6 +4916,9 @@
CLK_LOOKUP("measure", measure_clk.c, "debug"),
+ CLK_LOOKUP("gpll0", gpll0_clk_src.c, ""),
+ CLK_LOOKUP("gpll0_ao", gpll0_ao_clk_src.c, ""),
+
CLK_LOOKUP("dma_bam_pclk", gcc_bam_dma_ahb_clk.c, "msm_sps"),
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991f000.serial"),
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9924000.i2c"),
@@ -5173,6 +5197,25 @@
CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
"fda0a000.qcom,ispif"),
+ CLK_LOOKUP("vfe0_clk_src", vfe0_clk_src.c, "fda0a000.qcom,ispif"),
+ CLK_LOOKUP("camss_vfe_vfe0_clk", camss_vfe_vfe0_clk.c,
+ "fda0a000.qcom,ispif"),
+ CLK_LOOKUP("camss_csi_vfe0_clk", camss_csi_vfe0_clk.c,
+ "fda0a000.qcom,ispif"),
+ CLK_LOOKUP("vfe1_clk_src", vfe1_clk_src.c, "fda0a000.qcom,ispif"),
+ CLK_LOOKUP("camss_vfe_vfe1_clk", camss_vfe_vfe1_clk.c,
+ "fda0a000.qcom,ispif"),
+ CLK_LOOKUP("camss_csi_vfe1_clk", camss_csi_vfe1_clk.c,
+ "fda0a000.qcom,ispif"),
+ CLK_LOOKUP("csi0_src_clk", csi0_clk_src.c,
+ "fda0a000.qcom,ispif"),
+ CLK_LOOKUP("csi0_clk", camss_csi0_clk.c,
+ "fda0a000.qcom,ispif"),
+ CLK_LOOKUP("csi0_pix_clk", camss_csi0pix_clk.c,
+ "fda0a000.qcom,ispif"),
+ CLK_LOOKUP("csi0_rdi_clk", camss_csi0rdi_clk.c,
+ "fda0a000.qcom,ispif"),
+
/*VFE clocks*/
CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
"fda10000.qcom,vfe"),
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 527d73d..e3c11c5 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -90,16 +90,17 @@
continue;
rc = regulator_set_optimum_mode(r[i], ua[lvl_base + i]);
- if (rc < 0)
+ rc = rc > 0 ? 0 : rc;
+ if (rc)
goto set_mode_fail;
}
if (vdd_class->set_vdd && !vdd_class->num_regulators)
rc = vdd_class->set_vdd(vdd_class, level);
- if (rc < 0)
+ if (!rc)
vdd_class->cur_level = level;
- return 0;
+ return rc;
set_mode_fail:
regulator_set_voltage(r[i], uv[vdd_class->cur_level * n_reg + i],
diff --git a/arch/arm/mach-msm/include/mach/qseecomi.h b/arch/arm/mach-msm/include/mach/qseecomi.h
index a4021d4..688dea0 100644
--- a/arch/arm/mach-msm/include/mach/qseecomi.h
+++ b/arch/arm/mach-msm/include/mach/qseecomi.h
@@ -46,8 +46,12 @@
QSEOS_UNLOAD_SERV_IMAGE_COMMAND,
QSEOS_APP_REGION_NOTIFICATION,
QSEOS_REGISTER_LOG_BUF_COMMAND,
- QSEE_RPMB_PROVISION_KEY_COMMAND,
- QSEE_RPMB_ERASE_COMMAND,
+ QSEOS_RPMB_PROVISION_KEY_COMMAND,
+ QSEOS_RPMB_ERASE_COMMAND,
+ QSEOS_GENERATE_KEY = 0x11,
+ QSEOS_DELETE_KEY,
+ QSEOS_MAX_KEY_COUNT,
+ QSEOS_SET_KEY,
QSEOS_CMD_MAX = 0xEFFFFFFF
};
@@ -57,15 +61,6 @@
QSEOS_RESULT_FAILURE = 0xFFFFFFFF
};
-/* Key Management requests */
-enum qseecom_qceos_key_gen_cmd_id {
- QSEOS_GENERATE_KEY = 0x11,
- QSEOS_DELETE_KEY,
- QSEOS_MAX_KEY_COUNT,
- QSEOS_SET_KEY,
- QSEOS_KEY_CMD_MAX = 0xEFFFFFFF
-};
-
enum qseecom_pipe_type {
QSEOS_PIPE_ENC = 0x1,
QSEOS_PIPE_ENC_XTS = 0x2,
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index c0cca1d..64986d0 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -1013,6 +1013,7 @@
return -EINVAL;
}
+ memset(&ctl, 0, sizeof(ctl));
ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
for (i = 0; i < SRV_HASH_SIZE; i++) {
@@ -1241,6 +1242,7 @@
mode = mode_info->mode;
xprt_info = mode_info->xprt_info;
+ memset(&msg, 0, sizeof(msg));
msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
msg.cli.node_id = node_id;
msg.cli.port_id = port_id;
@@ -1295,6 +1297,7 @@
D("Remove server %08x:%08x - %08x:%08x",
server->name.service, server->name.instance,
rport_ptr->node_id, rport_ptr->port_id);
+ memset(&ctl, 0, sizeof(ctl));
ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
ctl.srv.service = server->name.service;
ctl.srv.instance = server->name.instance;
@@ -1313,6 +1316,7 @@
union rr_control_msg ctl;
int j;
+ memset(&ctl, 0, sizeof(ctl));
for (j = 0; j < RP_HASH_SIZE; j++) {
list_for_each_entry_safe(rport_ptr, tmp_rport_ptr,
&rt_entry->remote_port_list[j], list) {
@@ -1847,7 +1851,7 @@
process_done:
if (resume_tx) {
union rr_control_msg msg;
-
+ memset(&msg, 0, sizeof(msg));
msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
msg.cli.node_id = resume_tx_node_id;
msg.cli.port_id = resume_tx_port_id;
@@ -1900,6 +1904,7 @@
return -EINVAL;
}
+ memset(&ctl, 0, sizeof(ctl));
ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
ctl.srv.service = server->name.service;
ctl.srv.instance = server->name.instance;
@@ -1948,6 +1953,7 @@
return -ENODEV;
}
+ memset(&ctl, 0, sizeof(ctl));
ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
ctl.srv.service = server->name.service;
ctl.srv.instance = server->name.instance;
@@ -2433,6 +2439,7 @@
up_write(&local_ports_lock_lha2);
if (port_ptr->type == SERVER_PORT) {
+ memset(&msg, 0, sizeof(msg));
msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
msg.srv.service = port_ptr->port_name.service;
msg.srv.instance = port_ptr->port_name.instance;
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index 8a3ecb1..94281b1 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -573,7 +573,8 @@
{
int clk_ready = 0;
- if (of_find_property(desc->dev->of_node,
+ if (desc->ops->proxy_unvote &&
+ of_find_property(desc->dev->of_node,
"qcom,gpio-proxy-unvote",
NULL)) {
clk_ready = of_get_named_gpio(desc->dev->of_node,
@@ -780,7 +781,7 @@
"Invalid proxy unvote callback or a proxy timeout of 0"
" was specified or no proxy unvote IRQ was specified.\n");
- if (desc->proxy_unvote_irq > 0 && desc->ops->proxy_unvote) {
+ if (desc->proxy_unvote_irq) {
ret = request_threaded_irq(desc->proxy_unvote_irq,
NULL,
proxy_unvote_intr_handler,
diff --git a/block/row-iosched.c b/block/row-iosched.c
index 8e19c94..dfb46b4 100644
--- a/block/row-iosched.c
+++ b/block/row-iosched.c
@@ -396,7 +396,6 @@
"added urgent request (total on queue=%d)",
rqueue->nr_req);
rq->cmd_flags |= REQ_URGENT;
- WARN_ON(rqueue->nr_req > 1);
rd->pending_urgent_rq = rq;
}
} else
diff --git a/drivers/bif/qpnp-bsi.c b/drivers/bif/qpnp-bsi.c
index 5068a21..9d0abd2 100644
--- a/drivers/bif/qpnp-bsi.c
+++ b/drivers/bif/qpnp-bsi.c
@@ -56,6 +56,7 @@
atomic_t irq_flag[QPNP_BSI_IRQ_COUNT];
int batt_present_irq;
enum qpnp_vadc_channels batt_id_adc_channel;
+ struct qpnp_vadc_chip *vadc_dev;
};
#define QPNP_BSI_DRIVER_NAME "qcom,qpnp-bsi"
@@ -1343,7 +1344,8 @@
return -ENXIO;
}
- rc = qpnp_vadc_read(chip->batt_id_adc_channel, &adc_result);
+ rc = qpnp_vadc_read(chip->vadc_dev, chip->batt_id_adc_channel,
+ &adc_result);
if (!rc) {
vid_uV = adc_result.physical;
@@ -1672,8 +1674,11 @@
/* 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) {
+ chip->vadc_dev = qpnp_get_vadc(dev, "bsi");
+ if (IS_ERR(chip->vadc_dev)) {
+ rc = PTR_ERR(chip->vadc_dev);
+ if (rc != -EPROBE_DEFER)
+ pr_err("missing vadc property, rc=%d\n", rc);
/* Probe retry, do not print an error message */
goto cleanup_irqs;
}
diff --git a/drivers/coresight/coresight-cti.c b/drivers/coresight/coresight-cti.c
index d139583..2a06f0a 100644
--- a/drivers/coresight/coresight-cti.c
+++ b/drivers/coresight/coresight-cti.c
@@ -387,11 +387,77 @@
}
static DEVICE_ATTR(unmap_trigout, S_IWUSR, NULL, cti_store_unmap_trigout);
+static ssize_t cti_show_trigin(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long trig, ch;
+ uint32_t ctien;
+ ssize_t size = 0;
+
+ for (trig = 0; trig < CTI_MAX_TRIGGERS; trig++) {
+ ctien = cti_readl(drvdata, CTIINEN(trig));
+ for (ch = 0; ch < CTI_MAX_CHANNELS; ch++) {
+ if (ctien & (1 << ch)) {
+ /* Ensure we do not write more than PAGE_SIZE
+ * bytes of data including \n character and null
+ * terminator
+ */
+ size += scnprintf(&buf[size], PAGE_SIZE - size -
+ 1, " %#lx %#lx,", trig, ch);
+ if (size >= PAGE_SIZE - 2) {
+ dev_err(dev, "show buffer full\n");
+ goto err;
+ }
+
+ }
+ }
+ }
+err:
+ size += scnprintf(&buf[size], 2, "\n");
+ return size;
+}
+static DEVICE_ATTR(show_trigin, S_IRUGO, cti_show_trigin, NULL);
+
+static ssize_t cti_show_trigout(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long trig, ch;
+ uint32_t ctien;
+ ssize_t size = 0;
+
+ for (trig = 0; trig < CTI_MAX_TRIGGERS; trig++) {
+ ctien = cti_readl(drvdata, CTIOUTEN(trig));
+ for (ch = 0; ch < CTI_MAX_CHANNELS; ch++) {
+ if (ctien & (1 << ch)) {
+ /* Ensure we do not write more than PAGE_SIZE
+ * bytes of data including \n character and null
+ * terminator
+ */
+ size += scnprintf(&buf[size], PAGE_SIZE - size -
+ 1, " %#lx %#lx,", trig, ch);
+ if (size >= PAGE_SIZE - 2) {
+ dev_err(dev, "show buffer full\n");
+ goto err;
+ }
+
+ }
+ }
+ }
+err:
+ size += scnprintf(&buf[size], 2, "\n");
+ return size;
+}
+static DEVICE_ATTR(show_trigout, S_IRUGO, cti_show_trigout, NULL);
+
static struct attribute *cti_attrs[] = {
&dev_attr_map_trigin.attr,
&dev_attr_map_trigout.attr,
&dev_attr_unmap_trigin.attr,
&dev_attr_unmap_trigout.attr,
+ &dev_attr_show_trigin.attr,
+ &dev_attr_show_trigout.attr,
NULL,
};
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 96e759b..418c488 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -1198,7 +1198,28 @@
}
static const struct input_device_id dbs_ids[] = {
- { .driver_info = 1 },
+ /* multi-touch touchscreen */
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .evbit = { BIT_MASK(EV_ABS) },
+ .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] =
+ BIT_MASK(ABS_MT_POSITION_X) |
+ BIT_MASK(ABS_MT_POSITION_Y) },
+ },
+ /* touchpad */
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_KEYBIT |
+ INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
+ .absbit = { [BIT_WORD(ABS_X)] =
+ BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
+ },
+ /* Keypad */
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+ .evbit = { BIT_MASK(EV_KEY) },
+ },
{ },
};
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 184dd982..a28bf33 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -114,18 +114,6 @@
.long_ib_detect = 1,
};
-/* This set of registers are used for Hang detection
- * If the values of these registers are same after
- * KGSL_TIMEOUT_PART time, GPU hang is reported in
- * kernel log.
- * *****ALERT******ALERT********ALERT*************
- * Order of registers below is important, registers
- * from LONG_IB_DETECT_REG_INDEX_START to
- * LONG_IB_DETECT_REG_INDEX_END are used in long ib detection.
- */
-#define LONG_IB_DETECT_REG_INDEX_START 1
-#define LONG_IB_DETECT_REG_INDEX_END 5
-
unsigned int ft_detect_regs[FT_DETECT_REGS_COUNT];
/*
@@ -1722,6 +1710,9 @@
(device->pwrctrl.gpu_cx &&
regulator_is_enabled(device->pwrctrl.gpu_cx)));
+ /* Clear any GPU faults that might have been left over */
+ adreno_set_gpu_fault(adreno_dev, 0);
+
/* Power up the device */
kgsl_pwrctrl_enable(device);
@@ -1830,29 +1821,35 @@
*/
int adreno_reset(struct kgsl_device *device)
{
- int ret;
+ int ret = 0;
/* Try soft reset first */
- if (adreno_soft_reset(device) == 0)
- return 0;
+ if (adreno_soft_reset(device) != 0) {
+ KGSL_DEV_ERR_ONCE(device, "Device soft reset failed\n");
- /* If it failed, then pull the power */
- ret = adreno_stop(device);
- if (ret)
- return ret;
+ /* If it failed, then pull the power */
+ ret = adreno_stop(device);
+ if (ret)
+ return ret;
- ret = adreno_start(device);
+ ret = adreno_start(device);
- if (ret == 0) {
- /*
- * If active_cnt is non-zero then the system was active before
- * going into a reset - put it back in that state
- */
-
- if (atomic_read(&device->active_cnt))
- kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
+ if (ret)
+ return ret;
}
+ /*
+ * If active_cnt is non-zero then the system was active before
+ * going into a reset - put it back in that state
+ */
+
+ if (atomic_read(&device->active_cnt))
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
+
+ /* Set the page table back to the default page table */
+ kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable,
+ KGSL_MEMSTORE_GLOBAL);
+
return ret;
}
@@ -2310,6 +2307,13 @@
/* Stop the ringbuffer */
adreno_ringbuffer_stop(&adreno_dev->ringbuffer);
+ if (kgsl_pwrctrl_isenabled(device))
+ device->ftbl->irqctrl(device, 0);
+
+ kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
+
+ adreno_set_gpu_fault(adreno_dev, 0);
+
/* Delete the idle timer */
del_timer_sync(&device->idle_timer);
@@ -2391,12 +2395,20 @@
0x110, 0x110);
while (time_before(jiffies, wait)) {
+ /*
+ * If we fault, stop waiting and return an error. The dispatcher
+ * will clean up the fault from the work queue, but we need to
+ * make sure we don't block it by waiting for an idle that
+ * will never come.
+ */
+
+ if (adreno_gpu_fault(adreno_dev) != 0)
+ return -EDEADLK;
+
if (adreno_isidle(device))
return 0;
}
- kgsl_postmortem_dump(device, 0);
-
return -ETIMEDOUT;
}
@@ -2819,6 +2831,7 @@
.drawctxt_destroy = adreno_drawctxt_destroy,
.setproperty = adreno_setproperty,
.postmortem_dump = adreno_dump,
+ .drawctxt_sched = adreno_drawctxt_sched,
};
static struct platform_driver adreno_platform_driver = {
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 32e43b2..0363739 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -35,12 +35,11 @@
#define ADRENO_CHIPID_PATCH(_id) ((_id) & 0xFF)
/* Flags to control command packet settings */
-#define KGSL_CMD_FLAGS_NONE 0x00000000
-#define KGSL_CMD_FLAGS_PMODE 0x00000001
-#define KGSL_CMD_FLAGS_INTERNAL_ISSUE 0x00000002
-#define KGSL_CMD_FLAGS_GET_INT 0x00000004
-#define KGSL_CMD_FLAGS_PROFILE 0x00000008
-#define KGSL_CMD_FLAGS_EOF 0x00000100
+#define KGSL_CMD_FLAGS_NONE 0
+#define KGSL_CMD_FLAGS_PMODE BIT(0)
+#define KGSL_CMD_FLAGS_INTERNAL_ISSUE BIT(1)
+#define KGSL_CMD_FLAGS_WFI BIT(2)
+#define KGSL_CMD_FLAGS_PROFILE BIT(3)
/* Command identifiers */
#define KGSL_CONTEXT_TO_MEM_IDENTIFIER 0x2EADBEEF
@@ -96,6 +95,10 @@
TRACE_BUS_CTL,
};
+#define ADRENO_SOFT_FAULT 1
+#define ADRENO_HARD_FAULT 2
+#define ADRENO_TIMEOUT_FAULT 3
+
/*
* Maximum size of the dispatcher ringbuffer - the actual inflight size will be
* smaller then this but this size will allow for a larger range of inflight
@@ -110,7 +113,7 @@
* @state: Current state of the dispatcher (active or paused)
* @timer: Timer to monitor the progress of the command batches
* @inflight: Number of command batch operations pending in the ringbuffer
- * @fault: True if a HW fault was detected
+ * @fault: Non-zero if a fault was detected.
* @pending: Priority list of contexts waiting to submit command batches
* @plist_lock: Spin lock to protect the pending queue
* @cmdqueue: Queue of command batches currently flight
@@ -125,8 +128,9 @@
struct mutex mutex;
unsigned int state;
struct timer_list timer;
+ struct timer_list fault_timer;
unsigned int inflight;
- int fault;
+ atomic_t fault;
struct plist_head pending;
spinlock_t plist_lock;
struct kgsl_cmdbatch *cmdqueue[ADRENO_DISPATCH_CMDQUEUE_SIZE];
@@ -340,13 +344,16 @@
};
/* Fault Tolerance policy flags */
-#define KGSL_FT_OFF BIT(0)
-#define KGSL_FT_REPLAY BIT(1)
-#define KGSL_FT_SKIPIB BIT(2)
-#define KGSL_FT_SKIPFRAME BIT(3)
-#define KGSL_FT_DISABLE BIT(4)
-#define KGSL_FT_TEMP_DISABLE BIT(5)
-#define KGSL_FT_DEFAULT_POLICY (KGSL_FT_REPLAY + KGSL_FT_SKIPIB)
+#define KGSL_FT_OFF 0
+#define KGSL_FT_REPLAY 1
+#define KGSL_FT_SKIPIB 2
+#define KGSL_FT_SKIPFRAME 3
+#define KGSL_FT_DISABLE 4
+#define KGSL_FT_TEMP_DISABLE 5
+#define KGSL_FT_DEFAULT_POLICY (BIT(KGSL_FT_REPLAY) + BIT(KGSL_FT_SKIPIB))
+
+/* This internal bit is used to skip the PM dump on replayed command batches */
+#define KGSL_FT_SKIP_PMDUMP 31
/* Pagefault policy flags */
#define KGSL_FT_PAGEFAULT_INT_ENABLE BIT(0)
@@ -356,6 +363,14 @@
#define KGSL_FT_PAGEFAULT_DEFAULT_POLICY (KGSL_FT_PAGEFAULT_INT_ENABLE + \
KGSL_FT_PAGEFAULT_GPUHALT_ENABLE)
+#define ADRENO_FT_TYPES \
+ { BIT(KGSL_FT_OFF), "off" }, \
+ { BIT(KGSL_FT_REPLAY), "replay" }, \
+ { BIT(KGSL_FT_SKIPIB), "skipib" }, \
+ { BIT(KGSL_FT_SKIPFRAME), "skipframe" }, \
+ { BIT(KGSL_FT_DISABLE), "disable" }, \
+ { BIT(KGSL_FT_TEMP_DISABLE), "temp" }
+
extern struct adreno_gpudev adreno_a2xx_gpudev;
extern struct adreno_gpudev adreno_a3xx_gpudev;
@@ -425,6 +440,8 @@
void adreno_dispatcher_schedule(struct kgsl_device *device);
void adreno_dispatcher_pause(struct adreno_device *adreno_dev);
+void adreno_dispatcher_queue_context(struct kgsl_device *device,
+ struct adreno_context *drawctxt);
int adreno_reset(struct kgsl_device *device);
int adreno_ft_init_sysfs(struct kgsl_device *device);
@@ -741,4 +758,31 @@
return ADRENO_REG_REGISTER_MAX;
return adreno_dev->gpudev->reg_offsets->offsets[offset_name];
}
+
+/**
+ * adreno_gpu_fault() - Return the current state of the GPU
+ * @adreno_dev: A ponter to the adreno_device to query
+ *
+ * Return 0 if there is no fault or positive with the last type of fault that
+ * occurred
+ */
+static inline unsigned int adreno_gpu_fault(struct adreno_device *adreno_dev)
+{
+ smp_rmb();
+ return atomic_read(&adreno_dev->dispatcher.fault);
+}
+
+/**
+ * adreno_set_gpu_fault() - Set the current fault status of the GPU
+ * @adreno_dev: A pointer to the adreno_device to set
+ * @state: fault state to set
+ *
+ */
+static inline void adreno_set_gpu_fault(struct adreno_device *adreno_dev,
+ int state)
+{
+ atomic_set(&adreno_dev->dispatcher.fault, state);
+ smp_wmb();
+}
+
#endif /*__ADRENO_H */
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 8b75c4e..c4f81fa 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2596,7 +2596,7 @@
/* Clear the error */
kgsl_regwrite(device, A3XX_RBBM_AHB_CMD, (1 << 3));
- return;
+ goto done;
}
case A3XX_INT_RBBM_REG_TIMEOUT:
err = "RBBM: AHB register timeout";
@@ -2637,10 +2637,15 @@
case A3XX_INT_UCHE_OOB_ACCESS:
err = "UCHE: Out of bounds access";
break;
+ default:
+ return;
}
-
KGSL_DRV_CRIT(device, "%s\n", err);
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
+
+done:
+ /* Trigger a fault in the dispatcher - this will effect a restart */
+ adreno_dispatcher_irq_fault(device);
}
static void a3xx_cp_callback(struct adreno_device *adreno_dev, int irq)
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index e429934..13b4ba3 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -15,6 +15,7 @@
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/jiffies.h>
+#include <linux/err.h>
#include "kgsl.h"
#include "adreno.h"
@@ -41,6 +42,71 @@
/* Command batch timeout (in milliseconds) */
static unsigned int _cmdbatch_timeout = 2000;
+/* Interval for reading and comparing fault detection registers */
+static unsigned int _fault_timer_interval = 50;
+
+/* Local array for the current set of fault detect registers */
+static unsigned int fault_detect_regs[FT_DETECT_REGS_COUNT];
+
+/* The last retired global timestamp read during fault detect */
+static unsigned int fault_detect_ts;
+
+/**
+ * fault_detect_read() - Read the set of fault detect registers
+ * @device: Pointer to the KGSL device struct
+ *
+ * Read the set of fault detect registers and store them in the local array.
+ * This is for the initial values that are compared later with
+ * fault_detect_read_compare
+ */
+static void fault_detect_read(struct kgsl_device *device)
+{
+ int i;
+
+ fault_detect_ts = kgsl_readtimestamp(device, NULL,
+ KGSL_TIMESTAMP_RETIRED);
+
+ for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
+ if (ft_detect_regs[i] == 0)
+ continue;
+ kgsl_regread(device, ft_detect_regs[i],
+ &fault_detect_regs[i]);
+ }
+}
+
+/**
+ * fault_detect_read_compare() - Read the fault detect registers and compare
+ * them to the current value
+ * @device: Pointer to the KGSL device struct
+ *
+ * Read the set of fault detect registers and compare them to the current set
+ * of registers. Return 1 if any of the register values changed
+ */
+static int fault_detect_read_compare(struct kgsl_device *device)
+{
+ int i, ret = 0;
+ unsigned int ts;
+
+ for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
+ unsigned int val;
+
+ if (ft_detect_regs[i] == 0)
+ continue;
+ kgsl_regread(device, ft_detect_regs[i], &val);
+ if (val != fault_detect_regs[i])
+ ret = 1;
+ fault_detect_regs[i] = val;
+ }
+
+ ts = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
+ if (ts != fault_detect_ts)
+ ret = 1;
+
+ fault_detect_ts = ts;
+
+ return ret;
+}
+
/**
* adreno_dispatcher_get_cmdbatch() - Get a new command from a context queue
* @drawctxt: Pointer to the adreno draw context
@@ -55,12 +121,23 @@
mutex_lock(&drawctxt->mutex);
if (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) {
cmdbatch = drawctxt->cmdqueue[drawctxt->cmdqueue_head];
+
+ /*
+ * Don't dequeue a cmdbatch that is still waiting for other
+ * events
+ */
+ if (kgsl_cmdbatch_sync_pending(cmdbatch)) {
+ cmdbatch = ERR_PTR(-EAGAIN);
+ goto done;
+ }
+
drawctxt->cmdqueue_head =
CMDQUEUE_NEXT(drawctxt->cmdqueue_head,
ADRENO_CONTEXT_CMDQUEUE_SIZE);
drawctxt->queued--;
}
+done:
mutex_unlock(&drawctxt->mutex);
return cmdbatch;
@@ -162,9 +239,17 @@
ret = adreno_ringbuffer_submitcmd(adreno_dev, cmdbatch);
- /* Turn the GPU back off on failure. Sad face. */
- if (ret && dispatcher->inflight == 1)
- kgsl_active_count_put(device);
+ /*
+ * On the first command, if the submission was successful, then read the
+ * fault registers. If it failed then turn off the GPU. Sad face.
+ */
+
+ if (dispatcher->inflight == 1) {
+ if (ret == 0)
+ fault_detect_read(device);
+ else
+ kgsl_active_count_put(device);
+ }
mutex_unlock(&device->mutex);
@@ -191,6 +276,12 @@
cmdbatch->expires = jiffies +
msecs_to_jiffies(_cmdbatch_timeout);
mod_timer(&dispatcher->timer, cmdbatch->expires);
+
+ /* Start the fault detection timer */
+ if (adreno_dev->fast_hang_detect)
+ mod_timer(&dispatcher->fault_timer,
+ jiffies +
+ msecs_to_jiffies(_fault_timer_interval));
}
return 0;
@@ -208,19 +299,51 @@
{
struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
int count = 0;
+ int requeued = 0;
/*
* Each context can send a specific number of command batches per cycle
*/
- for ( ; count < _context_cmdbatch_burst &&
- dispatcher->inflight < _dispatcher_inflight; count++) {
+ while ((count < _context_cmdbatch_burst) &&
+ (dispatcher->inflight < _dispatcher_inflight)) {
int ret;
- struct kgsl_cmdbatch *cmdbatch =
- adreno_dispatcher_get_cmdbatch(drawctxt);
+ struct kgsl_cmdbatch *cmdbatch;
+
+ if (dispatcher->state != ADRENO_DISPATCHER_ACTIVE)
+ break;
+
+ if (adreno_gpu_fault(adreno_dev) != 0)
+ break;
+
+ cmdbatch = adreno_dispatcher_get_cmdbatch(drawctxt);
if (cmdbatch == NULL)
break;
+ /*
+ * adreno_context_get_cmdbatch returns -EAGAIN if the current
+ * cmdbatch has pending sync points so no more to do here.
+ * When the sync points are satisfied then the context will get
+ * reqeueued
+ */
+
+ if (IS_ERR(cmdbatch) && PTR_ERR(cmdbatch) == -EAGAIN) {
+ requeued = 1;
+ break;
+ }
+
+ /*
+ * If this is a synchronization submission then there are no
+ * commands to submit. Discard it and get the next item from
+ * the queue. Decrement count so this packet doesn't count
+ * against the burst for the context
+ */
+
+ if (cmdbatch->flags & KGSL_CONTEXT_SYNC) {
+ kgsl_cmdbatch_destroy(cmdbatch);
+ continue;
+ }
+
ret = sendcmd(adreno_dev, cmdbatch);
/*
@@ -232,8 +355,10 @@
*/
if (ret) {
adreno_dispatcher_requeue_cmdbatch(drawctxt, cmdbatch);
+ requeued = 1;
break;
}
+ count++;
}
/*
@@ -243,7 +368,7 @@
* reasonable to think that a busy context will stay busy.
*/
- if (count) {
+ if (count || requeued) {
dispatcher_queue_context(adreno_dev, drawctxt);
/*
@@ -255,7 +380,17 @@
wake_up_interruptible_all(&drawctxt->wq);
}
- return count;
+ /* Return the number of command batches processed */
+ if (count > 0)
+ return count;
+
+ /*
+ * If we didn't process anything because of a stall or an error
+ * return -1 so the issuecmds loop knows that we shouldn't
+ * keep trying to process it
+ */
+
+ return requeued ? -1 : 0;
}
/**
@@ -268,14 +403,18 @@
static int _adreno_dispatcher_issuecmds(struct adreno_device *adreno_dev)
{
struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
- /* Don't do anything if the dispatcher is paused */
- if (dispatcher->state != ADRENO_DISPATCHER_ACTIVE)
- return 0;
+ int last_id = 0;
while (dispatcher->inflight < _dispatcher_inflight) {
struct adreno_context *drawctxt = NULL;
+ /* Don't do anything if the dispatcher is paused */
+ if (dispatcher->state != ADRENO_DISPATCHER_ACTIVE)
+ break;
+
+ if (adreno_gpu_fault(adreno_dev) != 0)
+ break;
+
spin_lock(&dispatcher->plist_lock);
if (!plist_head_empty(&dispatcher->pending)) {
@@ -296,6 +435,21 @@
continue;
}
+ /*
+ * Don't loop endlessly on the same stalled context - if we see
+ * the same context twice in a row then assume that there is
+ * nothing else to do and bail. But don't forget to put the
+ * stalled context back on the queue otherwise it will get
+ * forgotten
+ */
+
+ if (last_id == drawctxt->base.id) {
+ dispatcher_queue_context(adreno_dev, drawctxt);
+ kgsl_context_put(&drawctxt->base);
+ break;
+ }
+
+ last_id = drawctxt->base.id;
dispatcher_context_sendcmds(adreno_dev, drawctxt);
kgsl_context_put(&drawctxt->base);
}
@@ -343,131 +497,41 @@
}
/**
- * adreno_dispatcher_replay() - Replay commands from the dispatcher queue
- * @adreno_dev: Pointer to the adreno device struct
+ * get_timestamp() - Return the next timestamp for the context
+ * @drawctxt - Pointer to an adreno draw context struct
+ * @cmdbatch - Pointer to a command batch
+ * @timestamp - Pointer to a timestamp value possibly passed from the user
*
- * Replay the commands from the dispatcher inflight queue. This is called after
- * a power down/up to recover from a fault
+ * Assign a timestamp based on the settings of the draw context and the command
+ * batch.
*/
-int adreno_dispatcher_replay(struct adreno_device *adreno_dev)
+static int get_timestamp(struct adreno_context *drawctxt,
+ struct kgsl_cmdbatch *cmdbatch, unsigned int *timestamp)
{
- struct kgsl_device *device = &adreno_dev->dev;
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
- struct kgsl_cmdbatch **replay;
- int i, ptr, count = 0;
-
- BUG_ON(!mutex_is_locked(&dispatcher->mutex));
-
- replay = kzalloc(sizeof(*replay) * dispatcher->inflight, GFP_KERNEL);
-
- /*
- * If we can't allocate enough memory for the replay commands then we
- * are in a bad way. Invalidate everything, reset the GPU and see ya
- * later alligator
- */
-
- if (replay == NULL) {
-
- ptr = dispatcher->head;
-
- while (ptr != dispatcher->tail) {
- struct kgsl_context *context =
- dispatcher->cmdqueue[ptr]->context;
-
- adreno_drawctxt_invalidate(device, context);
- ptr = CMDQUEUE_NEXT(ptr, ADRENO_DISPATCH_CMDQUEUE_SIZE);
- }
-
- /* Reset the dispatcher queue */
- dispatcher->inflight = 0;
- dispatcher->head = dispatcher->tail = 0;
-
- /* Reset the hardware */
- mutex_lock(&device->mutex);
-
- /*
- * If adreno_reset fails then the GPU is not alive and there
- * isn't anything we can do to recover at this point
- */
-
- BUG_ON(adreno_reset(device));
- mutex_unlock(&device->mutex);
-
+ /* Synchronization commands don't get a timestamp */
+ if (cmdbatch->flags & KGSL_CONTEXT_SYNC) {
+ *timestamp = 0;
return 0;
}
- ptr = dispatcher->head;
-
- while (ptr != dispatcher->tail) {
- struct kgsl_cmdbatch *cmdbatch = dispatcher->cmdqueue[ptr];
- struct adreno_context *drawctxt =
- ADRENO_CONTEXT(cmdbatch->context);
-
- if (cmdbatch->invalid)
- adreno_drawctxt_invalidate(device, cmdbatch->context);
-
- if (!kgsl_context_detached(cmdbatch->context) &&
- drawctxt->state == ADRENO_CONTEXT_STATE_ACTIVE) {
- /*
- * The context for the command batch is still valid -
- * add it to the replay list
- */
- replay[count++] = dispatcher->cmdqueue[ptr];
- } else {
- /*
- * Skip over invaliated or detached contexts - cancel
- * any pending events for the timestamp and destroy the
- * command batch
- */
- mutex_lock(&device->mutex);
- kgsl_cancel_events_timestamp(device, cmdbatch->context,
- cmdbatch->timestamp);
- mutex_unlock(&device->mutex);
-
- kgsl_cmdbatch_destroy(cmdbatch);
- }
-
- ptr = CMDQUEUE_NEXT(ptr, ADRENO_DISPATCH_CMDQUEUE_SIZE);
- }
-
- /* Reset the dispatcher queue */
- dispatcher->inflight = 0;
- dispatcher->head = dispatcher->tail = 0;
-
- mutex_lock(&device->mutex);
- BUG_ON(adreno_reset(device));
- mutex_unlock(&device->mutex);
-
- /* Replay the pending command buffers */
- for (i = 0; i < count; i++) {
- int ret = sendcmd(adreno_dev, replay[i]);
-
+ if (drawctxt->flags & CTXT_FLAGS_USER_GENERATED_TS) {
/*
- * I'm afraid that if we get an error during replay we
- * are not going to space today
+ * User specified timestamps need to be greater than the last
+ * issued timestamp in the context
*/
+ if (timestamp_cmp(drawctxt->timestamp, *timestamp) >= 0)
+ return -ERANGE;
- BUG_ON(ret);
- }
+ drawctxt->timestamp = *timestamp;
+ } else
+ drawctxt->timestamp++;
- /*
- * active_count will be set when we come into this function because
- * there were inflight commands. By virtue of setting ->inflight back
- * to 0 sendcmd() will increase the active count again on the first
- * submission. This active_count_put is needed to put the universe back
- * in balance and as a bonus it ensures that the hardware stays up for
- * the entire reset process
- */
- mutex_lock(&device->mutex);
- kgsl_active_count_put(device);
- mutex_unlock(&device->mutex);
-
- kfree(replay);
+ *timestamp = drawctxt->timestamp;
return 0;
}
/**
- * adreno_dispatcher_queue_cmd() - Queue a new command in the context
+ * adreno_dispactcher_queue_cmd() - Queue a new command in the context
* @adreno_dev: Pointer to the adreno device struct
* @drawctxt: Pointer to the adreno draw context
* @cmdbatch: Pointer to the command batch being submitted
@@ -489,6 +553,42 @@
return -EINVAL;
}
+ /*
+ * After skipping to the end of the frame we need to force the preamble
+ * to run (if it exists) regardless of the context state.
+ */
+
+ if (drawctxt->flags & CTXT_FLAGS_FORCE_PREAMBLE) {
+ set_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &cmdbatch->priv);
+ drawctxt->flags &= ~CTXT_FLAGS_FORCE_PREAMBLE;
+ }
+
+ /*
+ * If we are waiting for the end of frame and it hasn't appeared yet,
+ * then mark the command batch as skipped. It will still progress
+ * through the pipeline but it won't actually send any commands
+ */
+
+ if (drawctxt->flags & CTXT_FLAGS_SKIP_EOF) {
+ set_bit(CMDBATCH_FLAG_SKIP, &cmdbatch->priv);
+
+ /*
+ * If this command batch represents the EOF then clear the way
+ * for the dispatcher to continue submitting
+ */
+
+ if (cmdbatch->flags & KGSL_CONTEXT_END_OF_FRAME) {
+ drawctxt->flags &= ~CTXT_FLAGS_SKIP_EOF;
+
+ /*
+ * Force the preamble on the next command to ensure that
+ * the state is correct
+ */
+
+ drawctxt->flags |= CTXT_FLAGS_FORCE_PREAMBLE;
+ }
+ }
+
/* Wait for room in the context queue */
while (drawctxt->queued >= _context_cmdqueue_size) {
@@ -518,23 +618,23 @@
}
}
+ ret = get_timestamp(drawctxt, cmdbatch, timestamp);
+ if (ret) {
+ mutex_unlock(&drawctxt->mutex);
+ return ret;
+ }
+
+ cmdbatch->timestamp = *timestamp;
+
/*
- * If the UMD specified a timestamp then use that under the condition
- * that it is greater then the last queued timestamp in the context.
+ * Set the fault tolerance policy for the command batch - assuming the
+ * context hsn't disabled FT use the current device policy
*/
- if (drawctxt->flags & CTXT_FLAGS_USER_GENERATED_TS) {
- if (timestamp_cmp(drawctxt->timestamp, *timestamp) >= 0) {
- mutex_unlock(&drawctxt->mutex);
- return -ERANGE;
- }
-
- drawctxt->timestamp = *timestamp;
- } else
- drawctxt->timestamp++;
-
- cmdbatch->timestamp = drawctxt->timestamp;
- *timestamp = drawctxt->timestamp;
+ if (drawctxt->flags & CTXT_FLAGS_NO_FAULT_TOLERANCE)
+ set_bit(KGSL_FT_DISABLE, &cmdbatch->fault_policy);
+ else
+ cmdbatch->fault_policy = adreno_dev->ft_policy;
/* Put the command into the queue */
drawctxt->cmdqueue[drawctxt->cmdqueue_tail] = cmdbatch;
@@ -565,58 +665,442 @@
return 0;
}
-/**
- * dispatcher_do_fault() - Handle a GPU fault and reset the GPU
- * @device: Pointer to the KGSL device
- * @cmdbatch: Pointer to the command batch believed to be responsible for the
- * fault
- * @invalidate: Non zero if the current command should be invalidated
- *
- * Trigger a fault in the dispatcher and start the replay process
+/*
+ * If an IB inside of the command batch has a gpuaddr that matches the base
+ * passed in then zero the size which effectively skips it when it is submitted
+ * in the ringbuffer.
*/
-static void dispatcher_do_fault(struct kgsl_device *device,
- struct kgsl_cmdbatch *cmdbatch, int invalidate)
+static void cmdbatch_skip_ib(struct kgsl_cmdbatch *cmdbatch, unsigned int base)
+{
+ int i;
+
+ for (i = 0; i < cmdbatch->ibcount; i++) {
+ if (cmdbatch->ibdesc[i].gpuaddr == base) {
+ cmdbatch->ibdesc[i].sizedwords = 0;
+ return;
+ }
+ }
+}
+
+static void cmdbatch_skip_frame(struct kgsl_cmdbatch *cmdbatch,
+ struct kgsl_cmdbatch **replay, int count)
+{
+ struct adreno_context *drawctxt = ADRENO_CONTEXT(cmdbatch->context);
+ int skip = 1;
+ int i;
+
+ for (i = 0; i < count; i++) {
+
+ /*
+ * Only operate on command batches that belong to the
+ * faulting context
+ */
+
+ if (replay[i]->context->id != cmdbatch->context->id)
+ continue;
+
+ /*
+ * Skip all the command batches in this context until
+ * the EOF flag is seen. If the EOF flag is seen then
+ * force the preamble for the next command.
+ */
+
+ if (skip) {
+ set_bit(CMDBATCH_FLAG_SKIP, &replay[i]->priv);
+
+ if (replay[i]->flags & KGSL_CONTEXT_END_OF_FRAME)
+ skip = 0;
+ } else {
+ set_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &replay[i]->priv);
+ return;
+ }
+ }
+
+ /*
+ * If the EOF flag hasn't been seen yet then set the flag in the
+ * drawctxt to keep looking for it
+ */
+
+ if (skip && drawctxt)
+ drawctxt->flags |= CTXT_FLAGS_SKIP_EOF;
+
+ /*
+ * If we did see the EOF flag then force the preamble on for the
+ * next command issued on this context
+ */
+
+ if (!skip && drawctxt)
+ drawctxt->flags |= CTXT_FLAGS_FORCE_PREAMBLE;
+}
+
+static void remove_invalidated_cmdbatches(struct kgsl_device *device,
+ struct kgsl_cmdbatch **replay, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ struct kgsl_cmdbatch *cmd = replay[i];
+ struct adreno_context *drawctxt;
+
+ if (cmd == NULL)
+ continue;
+
+ drawctxt = ADRENO_CONTEXT(cmd->context);
+
+ if (kgsl_context_detached(cmd->context) ||
+ drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
+ replay[i] = NULL;
+
+ mutex_lock(&device->mutex);
+ kgsl_cancel_events_timestamp(device, cmd->context,
+ cmd->timestamp);
+ mutex_unlock(&device->mutex);
+
+ kgsl_cmdbatch_destroy(cmd);
+ }
+ }
+}
+
+static char _pidname[TASK_COMM_LEN];
+
+static inline const char *_kgsl_context_comm(struct kgsl_context *context)
+{
+ struct task_struct *task = NULL;
+
+ if (context)
+ task = find_task_by_vpid(context->pid);
+
+ if (task)
+ get_task_comm(_pidname, task);
+ else
+ snprintf(_pidname, TASK_COMM_LEN, "unknown");
+
+ return _pidname;
+}
+
+#define pr_fault(_d, _c, fmt, args...) \
+ dev_err((_d)->dev, "%s[%d]: " fmt, \
+ _kgsl_context_comm((_c)->context), \
+ (_c)->context->pid, ##args)
+
+
+static void adreno_fault_header(struct kgsl_device *device,
+ struct kgsl_cmdbatch *cmdbatch)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ unsigned int status, base, rptr, wptr, ib1base, ib2base, ib1sz, ib2sz;
+
+ kgsl_regread(device,
+ adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS),
+ &status);
+ kgsl_regread(device,
+ adreno_getreg(adreno_dev, ADRENO_REG_CP_RB_BASE),
+ &base);
+ kgsl_regread(device,
+ adreno_getreg(adreno_dev, ADRENO_REG_CP_RB_RPTR),
+ &rptr);
+ kgsl_regread(device,
+ adreno_getreg(adreno_dev, ADRENO_REG_CP_RB_WPTR),
+ &wptr);
+ kgsl_regread(device,
+ adreno_getreg(adreno_dev, ADRENO_REG_CP_IB1_BASE),
+ &ib1base);
+ kgsl_regread(device,
+ adreno_getreg(adreno_dev, ADRENO_REG_CP_IB1_BUFSZ),
+ &ib1sz);
+ kgsl_regread(device,
+ adreno_getreg(adreno_dev, ADRENO_REG_CP_IB2_BASE),
+ &ib2base);
+ kgsl_regread(device,
+ adreno_getreg(adreno_dev, ADRENO_REG_CP_IB2_BUFSZ),
+ &ib2sz);
+
+ trace_adreno_gpu_fault(cmdbatch->context->id, cmdbatch->timestamp,
+ status, rptr, wptr, ib1base, ib1sz, ib2base, ib2sz);
+
+ pr_fault(device, cmdbatch,
+ "gpu fault ctx %d ts %d status %8.8X rb %4.4x/%4.4x ib1 %8.8x/%4.4x ib2 %8.8x/%4.4x\n",
+ cmdbatch->context->id, cmdbatch->timestamp, status,
+ rptr, wptr, ib1base, ib1sz, ib2base, ib2sz);
+}
+
+static int dispatcher_do_fault(struct kgsl_device *device)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
- unsigned int reg;
+ unsigned int ptr;
+ unsigned int reg, base;
+ struct kgsl_cmdbatch **replay = NULL;
+ struct kgsl_cmdbatch *cmdbatch;
+ int ret, i, count = 0;
+ int fault, first = 0;
+ bool pagefault = false;
+ BUG_ON(dispatcher->inflight == 0);
- /* Stop the timers */
+ fault = atomic_xchg(&dispatcher->fault, 0);
+ if (fault == 0)
+ return 0;
+
+ /* Turn off all the timers */
del_timer_sync(&dispatcher->timer);
+ del_timer_sync(&dispatcher->fault_timer);
mutex_lock(&device->mutex);
- /*
- * There is an interesting race condition here - when a command batch
- * expires and we invaliate before we recover we run the risk of having
- * the UMD clean up the context and free memory that the GPU is still
- * using. Not that it is dangerous because we are a few microseconds
- * away from resetting, but it still ends up in pagefaults and log
- * messages and so on and so forth. To avoid this we mark the command
- * batch itself as invalid and then reset - the context will get
- * invalidated in the replay.
- */
+ cmdbatch = dispatcher->cmdqueue[dispatcher->head];
- if (invalidate)
- cmdbatch->invalid = 1;
+ trace_adreno_cmdbatch_fault(cmdbatch, fault);
/*
- * Stop the CP in its tracks - this ensures that we don't get activity
- * while we are trying to dump the state of the system
+ * If the fault was due to a timeout then stop the CP to ensure we don't
+ * get activity while we are trying to dump the state of the system
*/
+ if (fault == ADRENO_TIMEOUT_FAULT) {
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_ME_CNTL, ®);
+ reg |= (1 << 27) | (1 << 28);
+ adreno_writereg(adreno_dev, ADRENO_REG_CP_ME_CNTL, reg);
- adreno_readreg(adreno_dev, ADRENO_REG_CP_ME_CNTL, ®);
- reg |= (1 << 27) | (1 << 28);
- adreno_writereg(adreno_dev, ADRENO_REG_CP_ME_CNTL, reg);
+ /* Skip the PM dump for a timeout because it confuses people */
+ set_bit(KGSL_FT_SKIP_PMDUMP, &cmdbatch->fault_policy);
+ }
- kgsl_postmortem_dump(device, 0);
- kgsl_device_snapshot(device, 1);
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_IB1_BASE, &base);
+
+ /*
+ * Dump the postmortem and snapshot information if this is the first
+ * detected fault for the oldest active command batch
+ */
+
+ if (!test_bit(KGSL_FT_SKIP_PMDUMP, &cmdbatch->fault_policy)) {
+ adreno_fault_header(device, cmdbatch);
+
+ if (device->pm_dump_enable)
+ kgsl_postmortem_dump(device, 0);
+
+ kgsl_device_snapshot(device, 1);
+ }
+
mutex_unlock(&device->mutex);
- /* If we can't replay then bravely run away and die */
- if (adreno_dispatcher_replay(adreno_dev))
- BUG();
+ /* Allocate memory to store the inflight commands */
+ replay = kzalloc(sizeof(*replay) * dispatcher->inflight, GFP_KERNEL);
+
+ if (replay == NULL) {
+ unsigned int ptr = dispatcher->head;
+
+ while (ptr != dispatcher->tail) {
+ struct kgsl_context *context =
+ dispatcher->cmdqueue[ptr]->context;
+
+ adreno_drawctxt_invalidate(device, context);
+ kgsl_cmdbatch_destroy(dispatcher->cmdqueue[ptr]);
+
+ ptr = CMDQUEUE_NEXT(ptr, ADRENO_DISPATCH_CMDQUEUE_SIZE);
+ }
+
+ /*
+ * Set the replay count to zero - this will ensure that the
+ * hardware gets reset but nothing else goes played
+ */
+
+ count = 0;
+ goto replay;
+ }
+
+ /* Copy the inflight command batches into the temporary storage */
+ ptr = dispatcher->head;
+
+ while (ptr != dispatcher->tail) {
+ replay[count++] = dispatcher->cmdqueue[ptr];
+ ptr = CMDQUEUE_NEXT(ptr, ADRENO_DISPATCH_CMDQUEUE_SIZE);
+ }
+
+ /*
+ * For the purposes of replay, we assume that the oldest command batch
+ * that hasn't retired a timestamp is "hung".
+ */
+
+ cmdbatch = replay[0];
+
+ /*
+ * If FT is disabled for this cmdbatch invalidate immediately
+ */
+
+ if (test_bit(KGSL_FT_DISABLE, &cmdbatch->fault_policy) ||
+ test_bit(KGSL_FT_TEMP_DISABLE, &cmdbatch->fault_policy)) {
+ pr_fault(device, cmdbatch, "gpu skipped ctx %d ts %d\n",
+ cmdbatch->context->id, cmdbatch->timestamp);
+
+ adreno_drawctxt_invalidate(device, cmdbatch->context);
+ }
+
+ /*
+ * Set a flag so we don't print another PM dump if the cmdbatch fails
+ * again on replay
+ */
+
+ set_bit(KGSL_FT_SKIP_PMDUMP, &cmdbatch->fault_policy);
+
+ /*
+ * A hardware fault generally means something was deterministically
+ * wrong with the command batch - no point in trying to replay it
+ * Clear the replay bit and move on to the next policy level
+ */
+
+ if (fault == ADRENO_HARD_FAULT)
+ clear_bit(KGSL_FT_REPLAY, &(cmdbatch->fault_policy));
+
+ /*
+ * A timeout fault means the IB timed out - clear the policy and
+ * invalidate - this will clear the FT_SKIP_PMDUMP bit but that is okay
+ * because we won't see this cmdbatch again
+ */
+
+ if (fault == ADRENO_TIMEOUT_FAULT)
+ bitmap_zero(&cmdbatch->fault_policy, BITS_PER_LONG);
+
+ /*
+ * If the context had a GPU page fault then it is likely it would fault
+ * again if replayed
+ */
+
+ if (test_bit(KGSL_CONTEXT_PAGEFAULT, &cmdbatch->context->priv)) {
+ /* we'll need to resume the mmu later... */
+ pagefault = true;
+ clear_bit(KGSL_FT_REPLAY, &cmdbatch->fault_policy);
+ clear_bit(KGSL_CONTEXT_PAGEFAULT, &cmdbatch->context->priv);
+ }
+
+ /*
+ * Execute the fault tolerance policy. Each command batch stores the
+ * current fault policy that was set when it was queued.
+ * As the options are tried in descending priority
+ * (REPLAY -> SKIPIBS -> SKIPFRAME -> NOTHING) the bits are cleared
+ * from the cmdbatch policy so the next thing can be tried if the
+ * change comes around again
+ */
+
+ /* Replay the hanging command batch again */
+ if (test_and_clear_bit(KGSL_FT_REPLAY, &cmdbatch->fault_policy)) {
+ trace_adreno_cmdbatch_recovery(cmdbatch, BIT(KGSL_FT_REPLAY));
+ set_bit(KGSL_FT_REPLAY, &cmdbatch->fault_recovery);
+ goto replay;
+ }
+
+ /*
+ * Skip the last IB1 that was played but replay everything else.
+ * Note that the last IB1 might not be in the "hung" command batch
+ * because the CP may have caused a page-fault while it was prefetching
+ * the next IB1/IB2. walk all outstanding commands and zap the
+ * supposedly bad IB1 where ever it lurks.
+ */
+
+ if (test_and_clear_bit(KGSL_FT_SKIPIB, &cmdbatch->fault_policy)) {
+ trace_adreno_cmdbatch_recovery(cmdbatch, BIT(KGSL_FT_SKIPIB));
+ set_bit(KGSL_FT_SKIPIB, &cmdbatch->fault_recovery);
+
+ for (i = 0; i < count; i++) {
+ if (replay[i] != NULL)
+ cmdbatch_skip_ib(replay[i], base);
+ }
+
+ goto replay;
+ }
+
+ if (test_and_clear_bit(KGSL_FT_SKIPFRAME, &cmdbatch->fault_policy)) {
+ trace_adreno_cmdbatch_recovery(cmdbatch,
+ BIT(KGSL_FT_SKIPFRAME));
+ set_bit(KGSL_FT_SKIPFRAME, &cmdbatch->fault_recovery);
+
+ /*
+ * Skip all the pending command batches for this context until
+ * the EOF frame is seen
+ */
+ cmdbatch_skip_frame(cmdbatch, replay, count);
+ goto replay;
+ }
+
+ /* If we get here then all the policies failed */
+
+ pr_fault(device, cmdbatch, "gpu failed ctx %d ts %d\n",
+ cmdbatch->context->id, cmdbatch->timestamp);
+
+ /* Invalidate the context */
+ adreno_drawctxt_invalidate(device, cmdbatch->context);
+
+
+replay:
+ /* Reset the dispatcher queue */
+ dispatcher->inflight = 0;
+ dispatcher->head = dispatcher->tail = 0;
+
+ /* Reset the GPU */
+ mutex_lock(&device->mutex);
+
+ /* resume the MMU if it is stalled */
+ if (pagefault && device->mmu.mmu_ops->mmu_pagefault_resume != NULL)
+ device->mmu.mmu_ops->mmu_pagefault_resume(&device->mmu);
+
+ ret = adreno_reset(device);
+ mutex_unlock(&device->mutex);
+
+ /* If adreno_reset() fails then what hope do we have for the future? */
+ BUG_ON(ret);
+
+ /* Remove any pending command batches that have been invalidated */
+ remove_invalidated_cmdbatches(device, replay, count);
+
+ /* Replay the pending command buffers */
+ for (i = 0; i < count; i++) {
+
+ int ret;
+
+ if (replay[i] == NULL)
+ continue;
+
+ /*
+ * Force the preamble on the first command (if applicable) to
+ * avoid any strange stage issues
+ */
+
+ if (first == 0) {
+ set_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &replay[i]->priv);
+ first = 1;
+ }
+
+ /*
+ * Force each command batch to wait for idle - this avoids weird
+ * CP parse issues
+ */
+
+ set_bit(CMDBATCH_FLAG_WFI, &replay[i]->priv);
+
+ ret = sendcmd(adreno_dev, replay[i]);
+
+ /*
+ * If sending the command fails, then try to recover by
+ * invalidating the context
+ */
+
+ if (ret) {
+ pr_fault(device, replay[i],
+ "gpu reset failed ctx %d ts %d\n",
+ replay[i]->context->id, replay[i]->timestamp);
+
+ adreno_drawctxt_invalidate(device, replay[i]->context);
+ remove_invalidated_cmdbatches(device, &replay[i],
+ count - i);
+ }
+ }
+
+ mutex_lock(&device->mutex);
+ kgsl_active_count_put(device);
+ mutex_unlock(&device->mutex);
+
+ kfree(replay);
+
+ return 1;
}
static inline int cmdbatch_consumed(struct kgsl_cmdbatch *cmdbatch,
@@ -626,6 +1110,30 @@
(timestamp_cmp(retired, cmdbatch->timestamp) < 0));
}
+static void _print_recovery(struct kgsl_device *device,
+ struct kgsl_cmdbatch *cmdbatch)
+{
+ static struct {
+ unsigned int mask;
+ const char *str;
+ } flags[] = { ADRENO_FT_TYPES };
+
+ int i, nr = find_first_bit(&cmdbatch->fault_recovery, BITS_PER_LONG);
+ char *result = "unknown";
+
+ for (i = 0; i < ARRAY_SIZE(flags); i++) {
+ if (flags[i].mask == BIT(nr)) {
+ result = (char *) flags[i].str;
+ break;
+ }
+ }
+
+ pr_fault(device, cmdbatch,
+ "gpu %s ctx %d ts %d policy %lX\n",
+ result, cmdbatch->context->id, cmdbatch->timestamp,
+ cmdbatch->fault_recovery);
+}
+
/**
* adreno_dispatcher_work() - Master work handler for the dispatcher
* @work: Pointer to the work struct for the current work queue
@@ -639,7 +1147,7 @@
struct adreno_device *adreno_dev =
container_of(dispatcher, struct adreno_device, dispatcher);
struct kgsl_device *device = &adreno_dev->dev;
- int inv, count = 0;
+ int count = 0;
mutex_lock(&dispatcher->mutex);
@@ -667,6 +1175,14 @@
if (kgsl_context_detached(cmdbatch->context) ||
(timestamp_cmp(cmdbatch->timestamp, retired) <= 0)) {
+ /*
+ * If the cmdbatch in question had faulted announce its
+ * successful completion to the world
+ */
+
+ if (cmdbatch->fault_recovery != 0)
+ _print_recovery(device, cmdbatch);
+
trace_adreno_cmdbatch_retired(cmdbatch,
dispatcher->inflight - 1);
@@ -693,8 +1209,6 @@
}
count++;
-
- BUG_ON(dispatcher->inflight == 0 && dispatcher->fault);
continue;
}
@@ -703,17 +1217,23 @@
* is to blame. Invalidate it, reset and replay
*/
- if (dispatcher->fault) {
- dispatcher_do_fault(device, cmdbatch, 1);
+ if (dispatcher_do_fault(device))
goto done;
- }
/* Get the last consumed timestamp */
consumed = kgsl_readtimestamp(device, cmdbatch->context,
KGSL_TIMESTAMP_CONSUMED);
- /* Break here if fault detection is disabled for the context */
- if (drawctxt->flags & CTXT_FLAGS_NO_FAULT_TOLERANCE)
+ /*
+ * Break here if fault detection is disabled for the context or
+ * if the long running IB detection is disaled device wide
+ * Long running command buffers will be allowed to run to
+ * completion - but badly behaving command buffers (infinite
+ * shaders etc) can end up running forever.
+ */
+
+ if (!adreno_dev->long_ib_detect ||
+ drawctxt->flags & CTXT_FLAGS_NO_FAULT_TOLERANCE)
break;
/*
@@ -727,23 +1247,13 @@
/* Boom goes the dynamite */
- pr_err("-----------------------\n");
+ pr_fault(device, cmdbatch,
+ "gpu timeout ctx %d ts %d\n",
+ cmdbatch->context->id, cmdbatch->timestamp);
- pr_err("dispatcher: expired ctx=%d ts=%d consumed=%d retired=%d\n",
- cmdbatch->context->id, cmdbatch->timestamp, consumed,
- retired);
- pr_err("dispatcher: jiffies=%lu expired=%lu\n", jiffies,
- cmdbatch->expires);
+ adreno_set_gpu_fault(adreno_dev, ADRENO_TIMEOUT_FAULT);
- /*
- * If execution stopped after the current command batch was
- * consumed then invalidate the context for the current command
- * batch
- */
-
- inv = cmdbatch_consumed(cmdbatch, consumed, retired);
-
- dispatcher_do_fault(device, cmdbatch, inv);
+ dispatcher_do_fault(device);
break;
}
@@ -768,9 +1278,12 @@
struct kgsl_cmdbatch *cmdbatch
= dispatcher->cmdqueue[dispatcher->head];
+ /* Update the timeout timer for the next command batch */
mod_timer(&dispatcher->timer, cmdbatch->expires);
- } else
+ } else {
del_timer_sync(&dispatcher->timer);
+ del_timer_sync(&dispatcher->fault_timer);
+ }
/* Before leaving update the pwrscale information */
mutex_lock(&device->mutex);
@@ -788,6 +1301,60 @@
queue_work(device->work_queue, &dispatcher->work);
}
+/**
+ * adreno_dispatcher_queue_context() - schedule a drawctxt in the dispatcher
+ * device: pointer to the KGSL device
+ * drawctxt: pointer to the drawctxt to schedule
+ *
+ * Put a draw context on the dispatcher pending queue and schedule the
+ * dispatcher. This is used to reschedule changes that might have been blocked
+ * for sync points or other concerns
+ */
+void adreno_dispatcher_queue_context(struct kgsl_device *device,
+ struct adreno_context *drawctxt)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+ dispatcher_queue_context(adreno_dev, drawctxt);
+ adreno_dispatcher_schedule(device);
+}
+
+/*
+ * This is called on a regular basis while command batches are inflight. Fault
+ * detection registers are read and compared to the existing values - if they
+ * changed then the GPU is still running. If they are the same between
+ * subsequent calls then the GPU may have faulted
+ */
+
+void adreno_dispatcher_fault_timer(unsigned long data)
+{
+ struct adreno_device *adreno_dev = (struct adreno_device *) data;
+ struct kgsl_device *device = &adreno_dev->dev;
+ struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
+
+ /* Leave if the user decided to turn off fast hang detection */
+ if (adreno_dev->fast_hang_detect == 0)
+ return;
+
+ if (adreno_gpu_fault(adreno_dev)) {
+ adreno_dispatcher_schedule(device);
+ return;
+ }
+
+ /*
+ * Read the fault registers - if it returns 0 then they haven't changed
+ * so mark the dispatcher as faulted and schedule the work loop.
+ */
+
+ if (!fault_detect_read_compare(device)) {
+ adreno_set_gpu_fault(adreno_dev, ADRENO_SOFT_FAULT);
+ adreno_dispatcher_schedule(device);
+ } else {
+ mod_timer(&dispatcher->fault_timer,
+ jiffies + msecs_to_jiffies(_fault_timer_interval));
+ }
+}
+
/*
* This is called when the timer expires - it either means the GPU is hung or
* the IB is taking too long to execute
@@ -800,18 +1367,15 @@
adreno_dispatcher_schedule(device);
}
/**
- * adreno_dispatcher_fault_irq() - Trigger a fault in the dispatcher
+ * adreno_dispatcher_irq_fault() - Trigger a fault in the dispatcher
* @device: Pointer to the KGSL device
*
* Called from an interrupt context this will trigger a fault in the
- * dispatcher
+ * dispatcher for the oldest pending command batch
*/
-void adreno_dispatcher_fault_irq(struct kgsl_device *device)
+void adreno_dispatcher_irq_fault(struct kgsl_device *device)
{
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
- dispatcher->fault = 1;
+ adreno_set_gpu_fault(ADRENO_DEVICE(device), ADRENO_HARD_FAULT);
adreno_dispatcher_schedule(device);
}
@@ -863,6 +1427,8 @@
struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
del_timer_sync(&dispatcher->timer);
+ del_timer_sync(&dispatcher->fault_timer);
+
dispatcher->state = ADRENO_DISPATCHER_PAUSE;
}
@@ -878,6 +1444,7 @@
mutex_lock(&dispatcher->mutex);
del_timer_sync(&dispatcher->timer);
+ del_timer_sync(&dispatcher->fault_timer);
while (dispatcher->head != dispatcher->tail) {
kgsl_cmdbatch_destroy(dispatcher->cmdqueue[dispatcher->head]);
@@ -953,6 +1520,8 @@
_context_cmdbatch_burst);
static DISPATCHER_UINT_ATTR(cmdbatch_timeout, 0644, 0, _cmdbatch_timeout);
static DISPATCHER_UINT_ATTR(context_queue_wait, 0644, 0, _context_queue_wait);
+static DISPATCHER_UINT_ATTR(fault_detect_interval, 0644, 0,
+ _fault_timer_interval);
static struct attribute *dispatcher_attrs[] = {
&dispatcher_attr_inflight.attr,
@@ -960,6 +1529,7 @@
&dispatcher_attr_context_burst_count.attr,
&dispatcher_attr_cmdbatch_timeout.attr,
&dispatcher_attr_context_queue_wait.attr,
+ &dispatcher_attr_fault_detect_interval.attr,
NULL,
};
@@ -1024,6 +1594,9 @@
setup_timer(&dispatcher->timer, adreno_dispatcher_timer,
(unsigned long) adreno_dev);
+ setup_timer(&dispatcher->fault_timer, adreno_dispatcher_fault_timer,
+ (unsigned long) adreno_dev);
+
INIT_WORK(&dispatcher->work, adreno_dispatcher_work);
plist_head_init(&dispatcher->pending);
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 1a4310e..907d41f 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -461,6 +461,21 @@
}
/**
+ * adreno_drawctxt_sched() - Schedule a previously blocked context
+ * @device: pointer to a KGSL device
+ * @drawctxt: drawctxt to rechedule
+ *
+ * This function is called by the core when it knows that a previously blocked
+ * context has been unblocked. The default adreno response is to reschedule the
+ * context on the dispatcher
+ */
+void adreno_drawctxt_sched(struct kgsl_device *device,
+ struct kgsl_context *context)
+{
+ adreno_dispatcher_queue_context(device, ADRENO_CONTEXT(context));
+}
+
+/**
* adreno_drawctxt_detach(): detach a context from the GPU
* @context: Generic KGSL context container for the context
*
@@ -596,10 +611,8 @@
return ret;
}
- KGSL_CTXT_INFO(device, "from %d to %d flags %d\n",
- adreno_dev->drawctxt_active ?
- adreno_dev->drawctxt_active->base.id : 0,
- drawctxt ? drawctxt->base.id : 0, flags);
+ trace_adreno_drawctxt_switch(adreno_dev->drawctxt_active,
+ drawctxt, flags);
/* Save the old context */
ret = adreno_dev->gpudev->ctxt_save(adreno_dev,
diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h
index f8469e2..5c12676 100644
--- a/drivers/gpu/msm/adreno_drawctxt.h
+++ b/drivers/gpu/msm/adreno_drawctxt.h
@@ -54,6 +54,8 @@
#define CTXT_FLAGS_SKIP_EOF BIT(15)
/* Context no fault tolerance */
#define CTXT_FLAGS_NO_FAULT_TOLERANCE BIT(16)
+/* Force the preamble for the next submission */
+#define CTXT_FLAGS_FORCE_PREAMBLE BIT(17)
/* Symbolic table for the adreno draw context type */
#define ADRENO_DRAWCTXT_TYPES \
@@ -199,6 +201,9 @@
void adreno_drawctxt_destroy(struct kgsl_context *context);
+void adreno_drawctxt_sched(struct kgsl_device *device,
+ struct kgsl_context *context);
+
int adreno_drawctxt_switch(struct adreno_device *adreno_dev,
struct adreno_context *drawctxt,
unsigned int flags);
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 294ae76..8fb2830 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -396,8 +396,8 @@
int adreno_dump(struct kgsl_device *device, int manual)
{
- unsigned int cp_ib1_base, cp_ib1_bufsz;
- unsigned int cp_ib2_base, cp_ib2_bufsz;
+ unsigned int cp_ib1_base;
+ unsigned int cp_ib2_base;
phys_addr_t pt_base, cur_pt_base;
unsigned int cp_rb_base, cp_rb_ctrl, rb_count;
unsigned int cp_rb_wptr, cp_rb_rptr;
@@ -410,7 +410,6 @@
unsigned int ts_processed = 0xdeaddead;
struct kgsl_context *context;
unsigned int context_id;
- unsigned int rbbm_status;
static struct ib_list ib_list;
@@ -420,16 +419,10 @@
mb();
- if (device->pm_dump_enable) {
- msm_clk_dump_debug_info();
+ msm_clk_dump_debug_info();
- if (adreno_dev->gpudev->postmortem_dump)
- adreno_dev->gpudev->postmortem_dump(adreno_dev);
- }
-
- kgsl_regread(device,
- adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS),
- &rbbm_status);
+ if (adreno_dev->gpudev->postmortem_dump)
+ adreno_dev->gpudev->postmortem_dump(adreno_dev);
pt_base = kgsl_mmu_get_current_ptbase(&device->mmu);
cur_pt_base = pt_base;
@@ -451,29 +444,8 @@
adreno_getreg(adreno_dev, ADRENO_REG_CP_IB1_BASE),
&cp_ib1_base);
kgsl_regread(device,
- adreno_getreg(adreno_dev, ADRENO_REG_CP_IB1_BUFSZ),
- &cp_ib1_bufsz);
- kgsl_regread(device,
adreno_getreg(adreno_dev, ADRENO_REG_CP_IB2_BASE),
&cp_ib2_base);
- kgsl_regread(device,
- adreno_getreg(adreno_dev, ADRENO_REG_CP_IB2_BUFSZ),
- &cp_ib2_bufsz);
-
- trace_adreno_gpu_fault(rbbm_status, cp_rb_rptr, cp_rb_wptr,
- cp_ib1_base, cp_ib1_bufsz, cp_ib2_base, cp_ib2_bufsz);
-
- /* If postmortem dump is not enabled, dump minimal set and return */
- if (!device->pm_dump_enable) {
-
- KGSL_LOG_DUMP(device,
- "STATUS %08X | IB1:%08X/%08X | IB2: %08X/%08X"
- " | RPTR: %04X | WPTR: %04X\n",
- rbbm_status, cp_ib1_base, cp_ib1_bufsz, cp_ib2_base,
- cp_ib2_bufsz, cp_rb_rptr, cp_rb_wptr);
-
- return 0;
- }
kgsl_sharedmem_readl(&device->memstore,
(unsigned int *) &context_id,
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index dc1530a..1ad90fd 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -606,8 +606,8 @@
if (adreno_is_a20x(adreno_dev))
total_sizedwords += 2; /* CACHE_FLUSH */
- if (flags & KGSL_CMD_FLAGS_EOF)
- total_sizedwords += 2;
+ if (flags & KGSL_CMD_FLAGS_WFI)
+ total_sizedwords += 2; /* WFI */
if (profile_ready)
total_sizedwords += 6; /* space for pre_ib and post_ib */
@@ -737,6 +737,12 @@
GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0);
}
+ if (flags & KGSL_CMD_FLAGS_WFI) {
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ cp_type3_packet(CP_WAIT_FOR_IDLE, 1));
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0x00000000);
+ }
+
adreno_ringbuffer_submit(rb);
return 0;
@@ -1024,6 +1030,7 @@
struct kgsl_context *context;
struct adreno_context *drawctxt;
unsigned int start_index = 0;
+ int flags = KGSL_CMD_FLAGS_NONE;
int ret;
context = cmdbatch->context;
@@ -1039,10 +1046,23 @@
commands are stored in the first node of the IB chain. We can skip that
if a context switch hasn't occured */
- if (drawctxt->flags & CTXT_FLAGS_PREAMBLE &&
- adreno_dev->drawctxt_active == drawctxt)
+ if ((drawctxt->flags & CTXT_FLAGS_PREAMBLE) &&
+ !test_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &cmdbatch->priv) &&
+ (adreno_dev->drawctxt_active == drawctxt))
start_index = 1;
+ /*
+ * In skip mode don't issue the draw IBs but keep all the other
+ * accoutrements of a submision (including the interrupt) to keep
+ * the accounting sane. Set start_index and numibs to 0 to just
+ * generate the start and end markers and skip everything else
+ */
+
+ if (test_bit(CMDBATCH_FLAG_SKIP, &cmdbatch->priv)) {
+ start_index = 0;
+ numibs = 0;
+ }
+
cmds = link = kzalloc(sizeof(unsigned int) * (numibs * 3 + 4),
GFP_KERNEL);
if (!link) {
@@ -1061,7 +1081,17 @@
*cmds++ = ibdesc[0].sizedwords;
}
for (i = start_index; i < numibs; i++) {
- *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
+
+ /*
+ * Skip 0 sized IBs - these are presumed to have been removed
+ * from consideration by the FT policy
+ */
+
+ if (ibdesc[i].sizedwords == 0)
+ *cmds++ = cp_nop_packet(2);
+ else
+ *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
+
*cmds++ = ibdesc[i].gpuaddr;
*cmds++ = ibdesc[i].sizedwords;
}
@@ -1085,9 +1115,12 @@
if (ret)
goto done;
+ if (test_bit(CMDBATCH_FLAG_WFI, &cmdbatch->priv))
+ flags = KGSL_CMD_FLAGS_WFI;
+
ret = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
drawctxt,
- cmdbatch->flags,
+ flags,
&link[0], (cmds - link),
cmdbatch->timestamp);
diff --git a/drivers/gpu/msm/adreno_trace.h b/drivers/gpu/msm/adreno_trace.h
index 59aca2e..6079b61 100644
--- a/drivers/gpu/msm/adreno_trace.h
+++ b/drivers/gpu/msm/adreno_trace.h
@@ -29,15 +29,21 @@
__field(unsigned int, id)
__field(unsigned int, timestamp)
__field(unsigned int, queued)
+ __field(unsigned int, flags)
),
TP_fast_assign(
__entry->id = cmdbatch->context->id;
__entry->timestamp = cmdbatch->timestamp;
__entry->queued = queued;
+ __entry->flags = cmdbatch->flags;
),
TP_printk(
- "ctx=%u ts=%u queued=%u",
- __entry->id, __entry->timestamp, __entry->queued
+ "ctx=%u ts=%u queued=%u flags=%s",
+ __entry->id, __entry->timestamp, __entry->queued,
+ __entry->flags ? __print_flags(__entry->flags, "|",
+ { KGSL_CONTEXT_SYNC, "SYNC" },
+ { KGSL_CONTEXT_END_OF_FRAME, "EOF" })
+ : "none"
)
);
@@ -61,14 +67,78 @@
)
);
-DEFINE_EVENT(adreno_cmdbatch_template, adreno_cmdbatch_retired,
+DEFINE_EVENT(adreno_cmdbatch_template, adreno_cmdbatch_submitted,
TP_PROTO(struct kgsl_cmdbatch *cmdbatch, int inflight),
TP_ARGS(cmdbatch, inflight)
);
-DEFINE_EVENT(adreno_cmdbatch_template, adreno_cmdbatch_submitted,
+TRACE_EVENT(adreno_cmdbatch_retired,
TP_PROTO(struct kgsl_cmdbatch *cmdbatch, int inflight),
- TP_ARGS(cmdbatch, inflight)
+ TP_ARGS(cmdbatch, inflight),
+ TP_STRUCT__entry(
+ __field(unsigned int, id)
+ __field(unsigned int, timestamp)
+ __field(unsigned int, inflight)
+ __field(unsigned int, recovery)
+ ),
+ TP_fast_assign(
+ __entry->id = cmdbatch->context->id;
+ __entry->timestamp = cmdbatch->timestamp;
+ __entry->inflight = inflight;
+ __entry->recovery = cmdbatch->fault_recovery;
+ ),
+ TP_printk(
+ "ctx=%u ts=%u inflight=%u recovery=%s",
+ __entry->id, __entry->timestamp,
+ __entry->inflight,
+ __entry->recovery ?
+ __print_flags(__entry->recovery, "|",
+ ADRENO_FT_TYPES) : "none"
+ )
+);
+
+TRACE_EVENT(adreno_cmdbatch_fault,
+ TP_PROTO(struct kgsl_cmdbatch *cmdbatch, unsigned int fault),
+ TP_ARGS(cmdbatch, fault),
+ TP_STRUCT__entry(
+ __field(unsigned int, id)
+ __field(unsigned int, timestamp)
+ __field(unsigned int, fault)
+ ),
+ TP_fast_assign(
+ __entry->id = cmdbatch->context->id;
+ __entry->timestamp = cmdbatch->timestamp;
+ __entry->fault = fault;
+ ),
+ TP_printk(
+ "ctx=%u ts=%u type=%s",
+ __entry->id, __entry->timestamp,
+ __print_symbolic(__entry->fault,
+ { 0, "none" },
+ { ADRENO_SOFT_FAULT, "soft" },
+ { ADRENO_HARD_FAULT, "hard" },
+ { ADRENO_TIMEOUT_FAULT, "timeout" })
+ )
+);
+
+TRACE_EVENT(adreno_cmdbatch_recovery,
+ TP_PROTO(struct kgsl_cmdbatch *cmdbatch, unsigned int action),
+ TP_ARGS(cmdbatch, action),
+ TP_STRUCT__entry(
+ __field(unsigned int, id)
+ __field(unsigned int, timestamp)
+ __field(unsigned int, action)
+ ),
+ TP_fast_assign(
+ __entry->id = cmdbatch->context->id;
+ __entry->timestamp = cmdbatch->timestamp;
+ __entry->action = action;
+ ),
+ TP_printk(
+ "ctx=%u ts=%u action=%s",
+ __entry->id, __entry->timestamp,
+ __print_symbolic(__entry->action, ADRENO_FT_TYPES)
+ )
);
DECLARE_EVENT_CLASS(adreno_drawctxt_template,
@@ -139,12 +209,36 @@
)
);
+TRACE_EVENT(adreno_drawctxt_switch,
+ TP_PROTO(struct adreno_context *oldctx,
+ struct adreno_context *newctx,
+ unsigned int flags),
+ TP_ARGS(oldctx, newctx, flags),
+ TP_STRUCT__entry(
+ __field(unsigned int, oldctx)
+ __field(unsigned int, newctx)
+ __field(unsigned int, flags)
+ ),
+ TP_fast_assign(
+ __entry->oldctx = oldctx ? oldctx->base.id : 0;
+ __entry->newctx = newctx ? newctx->base.id : 0;
+ ),
+ TP_printk(
+ "oldctx=%u newctx=%u flags=%X",
+ __entry->oldctx, __entry->newctx, flags
+ )
+);
+
TRACE_EVENT(adreno_gpu_fault,
- TP_PROTO(unsigned int status, unsigned int rptr, unsigned int wptr,
+ TP_PROTO(unsigned int ctx, unsigned int ts,
+ unsigned int status, unsigned int rptr, unsigned int wptr,
unsigned int ib1base, unsigned int ib1size,
unsigned int ib2base, unsigned int ib2size),
- TP_ARGS(status, rptr, wptr, ib1base, ib1size, ib2base, ib2size),
+ TP_ARGS(ctx, ts, status, rptr, wptr, ib1base, ib1size, ib2base,
+ ib2size),
TP_STRUCT__entry(
+ __field(unsigned int, ctx)
+ __field(unsigned int, ts)
__field(unsigned int, status)
__field(unsigned int, rptr)
__field(unsigned int, wptr)
@@ -154,6 +248,8 @@
__field(unsigned int, ib2size)
),
TP_fast_assign(
+ __entry->ctx = ctx;
+ __entry->ts = ts;
__entry->status = status;
__entry->rptr = rptr;
__entry->wptr = wptr;
@@ -162,10 +258,10 @@
__entry->ib2base = ib2base;
__entry->ib2size = ib2size;
),
- TP_printk("status=%X RB=%X/%X IB1=%X/%X IB2=%X/%X",
- __entry->status, __entry->wptr, __entry->rptr,
- __entry->ib1base, __entry->ib1size, __entry->ib2base,
- __entry->ib2size)
+ TP_printk("ctx=%d ts=%d status=%X RB=%X/%X IB1=%X/%X IB2=%X/%X",
+ __entry->ctx, __entry->ts, __entry->status, __entry->wptr,
+ __entry->rptr, __entry->ib1base, __entry->ib1size,
+ __entry->ib2base, __entry->ib2size)
);
#endif /* _ADRENO_TRACE_H */
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 2624c16..35a03de 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -14,6 +14,7 @@
#include <linux/fb.h>
#include <linux/file.h>
#include <linux/fs.h>
+#include <linux/list.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/interrupt.h>
@@ -1398,30 +1399,372 @@
return result;
}
+/*
+ * KGSL command batch management
+ * A command batch is a single submission from userland. The cmdbatch
+ * encapsulates everything about the submission : command buffers, flags and
+ * sync points.
+ *
+ * Sync points are events that need to expire before the
+ * cmdbatch can be queued to the hardware. For each sync point a
+ * kgsl_cmdbatch_sync_event struct is created and added to a list in the
+ * cmdbatch. There can be multiple types of events both internal ones (GPU
+ * events) and external triggers. As the events expire the struct is deleted
+ * from the list. The GPU will submit the command batch as soon as the list
+ * goes empty indicating that all the sync points have been met.
+ */
+
+/**
+ * struct kgsl_cmdbatch_sync_event
+ * @type: Syncpoint type
+ * @node: Local list node for the cmdbatch sync point list
+ * @cmdbatch: Pointer to the cmdbatch that owns the sync event
+ * @context: Pointer to the KGSL context that owns the cmdbatch
+ * @timestamp: Pending timestamp for the event
+ * @handle: Pointer to a sync fence handle
+ * @device: Pointer to the KGSL device
+ * @lock: Spin lock to protect the sync event list
+ */
+struct kgsl_cmdbatch_sync_event {
+ int type;
+ struct list_head node;
+ struct kgsl_cmdbatch *cmdbatch;
+ struct kgsl_context *context;
+ unsigned int timestamp;
+ struct kgsl_sync_fence_waiter *handle;
+ struct kgsl_device *device;
+ spinlock_t lock;
+};
+
+/**
+ * kgsl_cmdbatch_destroy_object() - Destroy a cmdbatch object
+ * @kref: Pointer to the kref structure for this object
+ *
+ * Actually destroy a command batch object. Called from kgsl_cmdbatch_put
+ */
+void kgsl_cmdbatch_destroy_object(struct kref *kref)
+{
+ struct kgsl_cmdbatch *cmdbatch = container_of(kref,
+ struct kgsl_cmdbatch, refcount);
+
+ kgsl_context_put(cmdbatch->context);
+ kfree(cmdbatch->ibdesc);
+
+ kfree(cmdbatch);
+}
+EXPORT_SYMBOL(kgsl_cmdbatch_destroy_object);
+
+/*
+ * a generic function to retire a pending sync event and (possibly)
+ * kick the dispatcher
+ */
+static void kgsl_cmdbatch_sync_expire(struct kgsl_device *device,
+ struct kgsl_cmdbatch_sync_event *event)
+{
+ int sched = 0;
+
+ spin_lock(&event->cmdbatch->lock);
+ list_del(&event->node);
+ sched = list_empty(&event->cmdbatch->synclist) ? 1 : 0;
+ spin_unlock(&event->cmdbatch->lock);
+
+ /*
+ * if this is the last event in the list then tell
+ * the GPU device that the cmdbatch can be submitted
+ */
+
+ if (sched && device->ftbl->drawctxt_sched)
+ device->ftbl->drawctxt_sched(device, event->cmdbatch->context);
+}
+
+
+/*
+ * This function is called by the GPU event when the sync event timestamp
+ * expires
+ */
+static void kgsl_cmdbatch_sync_func(struct kgsl_device *device, void *priv,
+ u32 id, u32 timestamp, u32 type)
+{
+ struct kgsl_cmdbatch_sync_event *event = priv;
+
+ kgsl_cmdbatch_sync_expire(device, event);
+
+ kgsl_context_put(event->context);
+ kgsl_cmdbatch_put(event->cmdbatch);
+
+ kfree(event);
+}
+
+/**
+ * kgsl_cmdbatch_destroy() - Destroy a cmdbatch structure
+ * @cmdbatch: Pointer to the command batch object to destroy
+ *
+ * Start the process of destroying a command batch. Cancel any pending events
+ * and decrement the refcount.
+ */
+void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch)
+{
+ struct kgsl_cmdbatch_sync_event *event, *tmp;
+
+ spin_lock(&cmdbatch->lock);
+
+ /* Delete any pending sync points for this command batch */
+ list_for_each_entry_safe(event, tmp, &cmdbatch->synclist, node) {
+
+ if (event->type == KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP) {
+ /* Cancel the event if it still exists */
+ kgsl_cancel_event(cmdbatch->device, event->context,
+ event->timestamp, kgsl_cmdbatch_sync_func,
+ event);
+ } else if (event->type == KGSL_CMD_SYNCPOINT_TYPE_FENCE) {
+ if (kgsl_sync_fence_async_cancel(event->handle)) {
+ list_del(&event->node);
+ kfree(event);
+ kgsl_cmdbatch_put(cmdbatch);
+ }
+ }
+ }
+
+ spin_unlock(&cmdbatch->lock);
+ kgsl_cmdbatch_put(cmdbatch);
+}
+EXPORT_SYMBOL(kgsl_cmdbatch_destroy);
+
+/*
+ * A callback that gets registered with kgsl_sync_fence_async_wait and is fired
+ * when a fence is expired
+ */
+static void kgsl_cmdbatch_sync_fence_func(void *priv)
+{
+ struct kgsl_cmdbatch_sync_event *event = priv;
+
+ spin_lock(&event->lock);
+ kgsl_cmdbatch_sync_expire(event->device, event);
+ kgsl_cmdbatch_put(event->cmdbatch);
+ spin_unlock(&event->lock);
+ kfree(event);
+}
+
+/* kgsl_cmdbatch_add_sync_fence() - Add a new sync fence syncpoint
+ * @device: KGSL device
+ * @cmdbatch: KGSL cmdbatch to add the sync point to
+ * @priv: Private sructure passed by the user
+ *
+ * Add a new fence sync syncpoint to the cmdbatch.
+ */
+static int kgsl_cmdbatch_add_sync_fence(struct kgsl_device *device,
+ struct kgsl_cmdbatch *cmdbatch, void *priv)
+{
+ struct kgsl_cmd_syncpoint_fence *sync = priv;
+ struct kgsl_cmdbatch_sync_event *event;
+
+ event = kzalloc(sizeof(*event), GFP_KERNEL);
+
+ if (event == NULL)
+ return -ENOMEM;
+
+ kref_get(&cmdbatch->refcount);
+
+ event->type = KGSL_CMD_SYNCPOINT_TYPE_FENCE;
+ event->cmdbatch = cmdbatch;
+ event->device = device;
+ spin_lock_init(&event->lock);
+
+ /*
+ * Add it to the list first to account for the possiblity that the
+ * callback will happen immediately after the call to
+ * kgsl_sync_fence_async_wait
+ */
+
+ spin_lock(&cmdbatch->lock);
+ list_add(&event->node, &cmdbatch->synclist);
+ spin_unlock(&cmdbatch->lock);
+
+ /*
+ * There is a distinct race condition that can occur if the fence
+ * callback is fired before the function has a chance to return. The
+ * event struct would be freed before we could write event->handle and
+ * hilarity ensued. Protect against this by protecting the call to
+ * kgsl_sync_fence_async_wait and the kfree in the callback with a lock.
+ */
+
+ spin_lock(&event->lock);
+
+ event->handle = kgsl_sync_fence_async_wait(sync->fd,
+ kgsl_cmdbatch_sync_fence_func, event);
+
+
+ if (IS_ERR_OR_NULL(event->handle)) {
+ int ret = PTR_ERR(event->handle);
+
+ spin_lock(&cmdbatch->lock);
+ list_del(&event->node);
+ spin_unlock(&cmdbatch->lock);
+
+ kgsl_cmdbatch_put(cmdbatch);
+ spin_unlock(&event->lock);
+ kfree(event);
+
+ return ret;
+ }
+
+ spin_unlock(&event->lock);
+ return 0;
+}
+
+/* kgsl_cmdbatch_add_sync_timestamp() - Add a new sync point for a cmdbatch
+ * @device: KGSL device
+ * @cmdbatch: KGSL cmdbatch to add the sync point to
+ * @priv: Private sructure passed by the user
+ *
+ * Add a new sync point timestamp event to the cmdbatch.
+ */
+static int kgsl_cmdbatch_add_sync_timestamp(struct kgsl_device *device,
+ struct kgsl_cmdbatch *cmdbatch, void *priv)
+{
+ struct kgsl_cmd_syncpoint_timestamp *sync = priv;
+ struct kgsl_context *context = kgsl_context_get(cmdbatch->device,
+ sync->context_id);
+ struct kgsl_cmdbatch_sync_event *event;
+ int ret = -EINVAL;
+
+ if (context == NULL)
+ return -EINVAL;
+
+ /* Sanity check - you can't create a sync point on your own context */
+ if (context == cmdbatch->context) {
+ KGSL_DRV_ERR(device,
+ "Cannot create a sync point on your own context %d\n",
+ context->id);
+ goto done;
+ }
+
+ event = kzalloc(sizeof(*event), GFP_KERNEL);
+ if (event == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ kref_get(&cmdbatch->refcount);
+
+ event->type = KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP;
+ event->cmdbatch = cmdbatch;
+ event->context = context;
+ event->timestamp = sync->timestamp;
+
+ spin_lock(&cmdbatch->lock);
+ list_add(&event->node, &cmdbatch->synclist);
+ spin_unlock(&cmdbatch->lock);
+
+ mutex_lock(&device->mutex);
+ kgsl_active_count_get(device);
+ ret = kgsl_add_event(device, context->id, sync->timestamp,
+ kgsl_cmdbatch_sync_func, event, NULL);
+ kgsl_active_count_put(device);
+ mutex_unlock(&device->mutex);
+
+ if (ret) {
+ spin_lock(&cmdbatch->lock);
+ list_del(&event->node);
+ spin_unlock(&cmdbatch->lock);
+
+ kgsl_cmdbatch_put(cmdbatch);
+ kfree(event);
+ }
+
+done:
+ if (ret)
+ kgsl_context_put(context);
+
+ return ret;
+}
+
+/**
+ * kgsl_cmdbatch_add_sync() - Add a sync point to a command batch
+ * @device: Pointer to the KGSL device struct for the GPU
+ * @cmdbatch: Pointer to the cmdbatch
+ * @sync: Pointer to the user-specified struct defining the syncpoint
+ *
+ * Create a new sync point in the cmdbatch based on the user specified
+ * parameters
+ */
+static int kgsl_cmdbatch_add_sync(struct kgsl_device *device,
+ struct kgsl_cmdbatch *cmdbatch,
+ struct kgsl_cmd_syncpoint *sync)
+{
+ void *priv;
+ int ret, psize;
+ int (*func)(struct kgsl_device *device, struct kgsl_cmdbatch *cmdbatch,
+ void *priv);
+
+ switch (sync->type) {
+ case KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP:
+ psize = sizeof(struct kgsl_cmd_syncpoint_timestamp);
+ func = kgsl_cmdbatch_add_sync_timestamp;
+ break;
+ case KGSL_CMD_SYNCPOINT_TYPE_FENCE:
+ psize = sizeof(struct kgsl_cmd_syncpoint_fence);
+ func = kgsl_cmdbatch_add_sync_fence;
+ break;
+ default:
+ KGSL_DRV_ERR(device, "Invalid sync type 0x%x\n", sync->type);
+ return -EINVAL;
+ }
+
+ if (sync->size != psize) {
+ KGSL_DRV_ERR(device, "Invalid sync size %d\n", sync->size);
+ return -EINVAL;
+ }
+
+ priv = kzalloc(sync->size, GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+
+ if (copy_from_user(priv, sync->priv, sync->size)) {
+ kfree(priv);
+ return -EFAULT;
+ }
+
+ ret = func(device, cmdbatch, priv);
+ kfree(priv);
+
+ return ret;
+}
+
/**
* kgsl_cmdbatch_create() - Create a new cmdbatch structure
+ * @device: Pointer to a KGSL device struct
* @context: Pointer to a KGSL context struct
* @numibs: Number of indirect buffers to make room for in the cmdbatch
*
* Allocate an new cmdbatch structure and add enough room to store the list of
* indirect buffers
*/
-struct kgsl_cmdbatch *kgsl_cmdbatch_create(struct kgsl_context *context,
- int numibs)
+static struct kgsl_cmdbatch *kgsl_cmdbatch_create(struct kgsl_device *device,
+ struct kgsl_context *context, unsigned int flags,
+ unsigned int numibs)
{
struct kgsl_cmdbatch *cmdbatch = kzalloc(sizeof(*cmdbatch), GFP_KERNEL);
if (cmdbatch == NULL)
return ERR_PTR(-ENOMEM);
- cmdbatch->ibdesc = kzalloc(sizeof(*cmdbatch->ibdesc) * numibs,
- GFP_KERNEL);
- if (cmdbatch->ibdesc == NULL) {
- kfree(cmdbatch);
- return ERR_PTR(-ENOMEM);
+ if (!(flags & KGSL_CONTEXT_SYNC)) {
+ cmdbatch->ibdesc = kzalloc(sizeof(*cmdbatch->ibdesc) * numibs,
+ GFP_KERNEL);
+ if (cmdbatch->ibdesc == NULL) {
+ kfree(cmdbatch);
+ return ERR_PTR(-ENOMEM);
+ }
}
- cmdbatch->ibcount = numibs;
+ kref_init(&cmdbatch->refcount);
+ INIT_LIST_HEAD(&cmdbatch->synclist);
+ spin_lock_init(&cmdbatch->lock);
+
+ cmdbatch->device = device;
+ cmdbatch->ibcount = (flags & KGSL_CONTEXT_SYNC) ? 0 : numibs;
cmdbatch->context = context;
+ cmdbatch->flags = flags & ~KGSL_CONTEXT_SUBMIT_IB_LIST;
/*
* Increase the reference count on the context so it doesn't disappear
@@ -1450,15 +1793,22 @@
for (i = 0; i < cmdbatch->ibcount; i++) {
if (cmdbatch->ibdesc[i].sizedwords == 0) {
KGSL_DRV_ERR(dev_priv->device,
- "IB verification failed: Invalid size\n");
+ "invalid size ctx %d ib(%d) %X/%X\n",
+ cmdbatch->context->id, i,
+ cmdbatch->ibdesc[i].gpuaddr,
+ cmdbatch->ibdesc[i].sizedwords);
+
return false;
}
if (!kgsl_mmu_gpuaddr_in_range(private->pagetable,
cmdbatch->ibdesc[i].gpuaddr)) {
KGSL_DRV_ERR(dev_priv->device,
- "IB verification failed: invalid address 0x%X\n",
- cmdbatch->ibdesc[i].gpuaddr);
+ "Invalid address ctx %d ib(%d) %X/%X\n",
+ cmdbatch->context->id, i,
+ cmdbatch->ibdesc[i].gpuaddr,
+ cmdbatch->ibdesc[i].sizedwords);
+
return false;
}
}
@@ -1468,16 +1818,19 @@
/**
* _kgsl_cmdbatch_create_legacy() - Create a cmdbatch from a legacy ioctl struct
+ * @device: Pointer to the KGSL device struct for the GPU
* @context: Pointer to the KGSL context that issued the command batch
* @param: Pointer to the kgsl_ringbuffer_issueibcmds struct that the user sent
*
* Create a command batch from the legacy issueibcmds format.
*/
static struct kgsl_cmdbatch *_kgsl_cmdbatch_create_legacy(
+ struct kgsl_device *device,
struct kgsl_context *context,
struct kgsl_ringbuffer_issueibcmds *param)
{
- struct kgsl_cmdbatch *cmdbatch = kgsl_cmdbatch_create(context, 1);
+ struct kgsl_cmdbatch *cmdbatch =
+ kgsl_cmdbatch_create(device, context, param->flags, 1);
if (IS_ERR(cmdbatch))
return cmdbatch;
@@ -1492,31 +1845,64 @@
/**
* _kgsl_cmdbatch_create() - Create a cmdbatch from a ioctl struct
- * @device: Pointer to the KGSL device for the GPU
+ * @device: Pointer to the KGSL device struct for the GPU
* @context: Pointer to the KGSL context that issued the command batch
- * @param: Pointer to the kgsl_ringbuffer_issueibcmds struct that the user sent
+ * @flags: Flags passed in from the user command
+ * @cmdlist: Pointer to the list of commands from the user
+ * @numcmds: Number of commands in the list
+ * @synclist: Pointer to the list of syncpoints from the user
+ * @numsyncs: Number of syncpoints in the list
*
* Create a command batch from the standard issueibcmds format sent by the user.
*/
-struct kgsl_cmdbatch *_kgsl_cmdbatch_create(struct kgsl_device *device,
+static struct kgsl_cmdbatch *_kgsl_cmdbatch_create(struct kgsl_device *device,
struct kgsl_context *context,
- struct kgsl_ringbuffer_issueibcmds *param)
+ unsigned int flags,
+ unsigned int cmdlist, unsigned int numcmds,
+ unsigned int synclist, unsigned int numsyncs)
{
struct kgsl_cmdbatch *cmdbatch =
- kgsl_cmdbatch_create(context, param->numibs);
+ kgsl_cmdbatch_create(device, context, flags, numcmds);
+ int ret = 0;
if (IS_ERR(cmdbatch))
return cmdbatch;
- if (copy_from_user(cmdbatch->ibdesc, (void *)param->ibdesc_addr,
- sizeof(struct kgsl_ibdesc) * param->numibs)) {
- KGSL_DRV_ERR(device,
- "Unable to copy the IB userspace commands\n");
- kgsl_cmdbatch_destroy(cmdbatch);
- return ERR_PTR(-EFAULT);
+ if (!(flags & KGSL_CONTEXT_SYNC)) {
+ if (copy_from_user(cmdbatch->ibdesc, (void __user *) cmdlist,
+ sizeof(struct kgsl_ibdesc) * numcmds)) {
+ ret = -EFAULT;
+ goto done;
+ }
}
- cmdbatch->flags = param->flags & ~KGSL_CONTEXT_SUBMIT_IB_LIST;
+ if (synclist && numsyncs) {
+ struct kgsl_cmd_syncpoint sync;
+ void __user *uptr = (void __user *) synclist;
+ int i;
+
+ for (i = 0; i < numsyncs; i++) {
+ memset(&sync, 0, sizeof(sync));
+
+ if (copy_from_user(&sync, uptr, sizeof(sync))) {
+ ret = -EFAULT;
+ break;
+ }
+
+ ret = kgsl_cmdbatch_add_sync(device, cmdbatch, &sync);
+
+ if (ret)
+ break;
+
+ uptr += sizeof(sync);
+ }
+ }
+
+done:
+ if (ret) {
+ kgsl_cmdbatch_destroy(cmdbatch);
+ return ERR_PTR(ret);
+ }
return cmdbatch;
}
@@ -1530,12 +1916,14 @@
struct kgsl_cmdbatch *cmdbatch;
long result = -EINVAL;
+ /* The legacy functions don't support synchronization commands */
+ if (param->flags & KGSL_CONTEXT_SYNC)
+ return -EINVAL;
+
+ /* Get the context */
context = kgsl_context_get_owner(dev_priv, param->drawctxt_id);
- if (context == NULL) {
- KGSL_DRV_ERR(device,
- "Could not find context %d\n", param->drawctxt_id);
+ if (context == NULL)
goto done;
- }
if (param->flags & KGSL_CONTEXT_SUBMIT_IB_LIST) {
/*
@@ -1543,15 +1931,13 @@
* submission
*/
- if (param->numibs == 0 || param->numibs > 100000) {
- KGSL_DRV_ERR(device,
- "Invalid number of IBs %d\n", param->numibs);
+ if (param->numibs == 0 || param->numibs > KGSL_MAX_NUMIBS)
goto done;
- }
- cmdbatch = _kgsl_cmdbatch_create(device, context, param);
+ cmdbatch = _kgsl_cmdbatch_create(device, context, param->flags,
+ param->ibdesc_addr, param->numibs, 0, 0);
} else
- cmdbatch = _kgsl_cmdbatch_create_legacy(context, param);
+ cmdbatch = _kgsl_cmdbatch_create_legacy(device, context, param);
if (IS_ERR(cmdbatch)) {
result = PTR_ERR(cmdbatch);
@@ -1559,11 +1945,57 @@
}
/* Run basic sanity checking on the command */
- if (!_kgsl_cmdbatch_verify(dev_priv, cmdbatch)) {
- KGSL_DRV_ERR(device, "Unable to verify the IBs\n");
+ if (!_kgsl_cmdbatch_verify(dev_priv, cmdbatch))
goto free_cmdbatch;
+
+ result = dev_priv->device->ftbl->issueibcmds(dev_priv, context,
+ cmdbatch, ¶m->timestamp);
+
+free_cmdbatch:
+ if (result)
+ kgsl_cmdbatch_destroy(cmdbatch);
+
+done:
+ kgsl_context_put(context);
+ return result;
+}
+
+static long kgsl_ioctl_submit_commands(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data)
+{
+ struct kgsl_submit_commands *param = data;
+ struct kgsl_device *device = dev_priv->device;
+ struct kgsl_context *context;
+ struct kgsl_cmdbatch *cmdbatch;
+
+ long result = -EINVAL;
+
+ /* The number of IBs are completely ignored for sync commands */
+ if (!(param->flags & KGSL_CONTEXT_SYNC)) {
+ if (param->numcmds == 0 || param->numcmds > KGSL_MAX_NUMIBS)
+ return -EINVAL;
+ } else if (param->numcmds != 0) {
+ KGSL_DEV_ERR_ONCE(device,
+ "Commands specified with the SYNC flag. They will be ignored\n");
}
+ context = kgsl_context_get_owner(dev_priv, param->context_id);
+ if (context == NULL)
+ return -EINVAL;
+
+ cmdbatch = _kgsl_cmdbatch_create(device, context, param->flags,
+ (unsigned int) param->cmdlist, param->numcmds,
+ (unsigned int) param->synclist, param->numsyncs);
+
+ if (IS_ERR(cmdbatch)) {
+ result = PTR_ERR(cmdbatch);
+ goto done;
+ }
+
+ /* Run basic sanity checking on the command */
+ if (!_kgsl_cmdbatch_verify(dev_priv, cmdbatch))
+ goto free_cmdbatch;
+
result = dev_priv->device->ftbl->issueibcmds(dev_priv, context,
cmdbatch, ¶m->timestamp);
@@ -2823,6 +3255,8 @@
KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
KGSL_IOCTL_FUNC(IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS,
kgsl_ioctl_rb_issueibcmds, 0),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_SUBMIT_COMMANDS,
+ kgsl_ioctl_submit_commands, 0),
KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_READTIMESTAMP,
kgsl_ioctl_cmdstream_readtimestamp,
KGSL_IOCTL_LOCK),
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index de647d5..2e9d52e 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -78,6 +78,8 @@
#define KGSL_MEMFREE_HIST_SIZE ((int)(PAGE_SIZE * 2))
+#define KGSL_MAX_NUMIBS 100000
+
struct kgsl_memfree_hist_elem {
unsigned int pid;
unsigned int gpuaddr;
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index f5b27d0..cd9c4f7 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -134,6 +134,8 @@
int (*postmortem_dump) (struct kgsl_device *device, int manual);
int (*next_event)(struct kgsl_device *device,
struct kgsl_event *event);
+ void (*drawctxt_sched)(struct kgsl_device *device,
+ struct kgsl_context *context);
};
/* MH register values */
@@ -159,23 +161,53 @@
/**
* struct kgsl_cmdbatch - KGSl command descriptor
+ * @device: KGSL GPU device that the command was created for
* @context: KGSL context that created the command
- * @timestamp: Timestamp assigned to the command (currently unused)
+ * @timestamp: Timestamp assigned to the command
* @flags: flags
+ * @priv: Internal flags
+ * @fault_policy: Internal policy describing how to handle this command in case
+ * of a fault
+ * @fault_recovery: recovery actions actually tried for this batch
* @ibcount: Number of IBs in the command list
* @ibdesc: Pointer to the list of IBs
* @expires: Point in time when the cmdbatch is considered to be hung
* @invalid: non-zero if the dispatcher determines the command and the owning
* context should be invalidated
+ * @refcount: kref structure to maintain the reference count
+ * @synclist: List of context/timestamp tuples to wait for before issuing
+ *
+ * This struture defines an atomic batch of command buffers issued from
+ * userspace.
*/
struct kgsl_cmdbatch {
+ struct kgsl_device *device;
struct kgsl_context *context;
+ spinlock_t lock;
uint32_t timestamp;
uint32_t flags;
+ unsigned long priv;
+ unsigned long fault_policy;
+ unsigned long fault_recovery;
uint32_t ibcount;
struct kgsl_ibdesc *ibdesc;
unsigned long expires;
int invalid;
+ struct kref refcount;
+ struct list_head synclist;
+};
+
+/**
+ * enum kgsl_cmdbatch_priv - Internal cmdbatch flags
+ * @CMDBATCH_FLAG_SKIP - skip the entire command batch
+ * @CMDBATCH_FLAG_FORCE_PREAMBLE - Force the preamble on for the cmdbatch
+ * @CMDBATCH_FLAG_WFI - Force wait-for-idle for the submission
+ */
+
+enum kgsl_cmdbatch_priv {
+ CMDBATCH_FLAG_SKIP = 0,
+ CMDBATCH_FLAG_FORCE_PREAMBLE,
+ CMDBATCH_FLAG_WFI,
};
struct kgsl_device {
@@ -258,6 +290,7 @@
struct work_struct ts_expired_ws;
struct list_head events;
struct list_head events_pending_list;
+ unsigned int events_last_timestamp;
s64 on_time;
/* Postmortem Control switches */
@@ -368,6 +401,9 @@
int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts,
kgsl_event_func func, void *priv, void *owner);
+void kgsl_cancel_event(struct kgsl_device *device, struct kgsl_context *context,
+ unsigned int timestamp, kgsl_event_func func, void *priv);
+
static inline void kgsl_process_add_stats(struct kgsl_process_private *priv,
unsigned int type, size_t size)
{
@@ -611,20 +647,39 @@
kgsl_signal_event(device, context, timestamp, KGSL_EVENT_CANCELLED);
}
-/**
- * kgsl_cmdbatch_destroy() - Destroy a command batch structure
- * @cmdbatch: Pointer to the command batch to destroy
- *
- * Destroy and free a command batch
- */
-static inline void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch)
-{
- if (cmdbatch) {
- kgsl_context_put(cmdbatch->context);
- kfree(cmdbatch->ibdesc);
- }
+void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch);
- kfree(cmdbatch);
+void kgsl_cmdbatch_destroy_object(struct kref *kref);
+
+/**
+ * kgsl_cmdbatch_put() - Decrement the refcount for a command batch object
+ * @cmdbatch: Pointer to the command batch object
+ */
+static inline void kgsl_cmdbatch_put(struct kgsl_cmdbatch *cmdbatch)
+{
+ if (cmdbatch)
+ kref_put(&cmdbatch->refcount, kgsl_cmdbatch_destroy_object);
+}
+
+/**
+ * kgsl_cmdbatch_sync_pending() - return true if the cmdbatch is waiting
+ * @cmdbatch: Pointer to the command batch object to check
+ *
+ * Return non-zero if the specified command batch is still waiting for sync
+ * point dependencies to be satisfied
+ */
+static inline int kgsl_cmdbatch_sync_pending(struct kgsl_cmdbatch *cmdbatch)
+{
+ int ret;
+
+ if (cmdbatch == NULL)
+ return 0;
+
+ spin_lock(&cmdbatch->lock);
+ ret = list_empty(&cmdbatch->synclist) ? 0 : 1;
+ spin_unlock(&cmdbatch->lock);
+
+ return ret;
}
#endif /* __KGSL_DEVICE_H */
diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c
index e4f502a..c7ac0ad 100644
--- a/drivers/gpu/msm/kgsl_events.c
+++ b/drivers/gpu/msm/kgsl_events.c
@@ -48,7 +48,8 @@
{
int id = event->context ? event->context->id : KGSL_MEMSTORE_GLOBAL;
- trace_kgsl_fire_event(id, timestamp, type, jiffies - event->created);
+ trace_kgsl_fire_event(id, timestamp, type, jiffies - event->created,
+ event->func);
if (event->func)
event->func(device, event->priv, id, timestamp, type);
@@ -235,7 +236,7 @@
*/
if (timestamp_cmp(cur_ts, ts) >= 0) {
- trace_kgsl_fire_event(id, cur_ts, ts, 0);
+ trace_kgsl_fire_event(id, cur_ts, ts, 0, func);
func(device, priv, id, ts, KGSL_EVENT_TIMESTAMP_RETIRED);
kgsl_context_put(context);
@@ -266,7 +267,7 @@
event->owner = owner;
event->created = jiffies;
- trace_kgsl_register_event(id, ts);
+ trace_kgsl_register_event(id, ts, func);
/* Add the event to either the owning context or the global list */
@@ -333,7 +334,11 @@
void *priv)
{
struct kgsl_event *event;
- struct list_head *head = _get_list_head(device, context);
+ struct list_head *head;
+
+ BUG_ON(!mutex_is_locked(&device->mutex));
+
+ head = _get_list_head(device, context);
event = _find_event(device, head, timestamp, func, priv);
@@ -400,10 +405,19 @@
struct kgsl_context *context, *tmp;
uint32_t timestamp;
+ /*
+ * Bail unless the global timestamp has advanced. We can safely do this
+ * outside of the mutex for speed
+ */
+
+ timestamp = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
+ if (timestamp == device->events_last_timestamp)
+ return;
+
mutex_lock(&device->mutex);
- /* Process expired global events */
- timestamp = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
+ device->events_last_timestamp = timestamp;
+
_retire_events(device, &device->events, timestamp);
_mark_next_event(device, &device->events);
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 103736d..e296784 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -423,8 +423,12 @@
* the GPU and trigger a snapshot. To stall the transaction return
* EBUSY error.
*/
- if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_GPUHALT_ENABLE)
+ if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_GPUHALT_ENABLE) {
+ /* turn off GPU IRQ so we don't get faults from it too */
+ kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
+ adreno_dispatcher_irq_fault(device);
ret = -EBUSY;
+ }
done:
return ret;
}
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
index b7d7235..dc3ad21 100644
--- a/drivers/gpu/msm/kgsl_sync.c
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/err.h>
#include <linux/file.h>
#include <linux/sched.h>
#include <linux/slab.h>
@@ -281,3 +282,65 @@
{
sync_timeline_destroy(context->timeline);
}
+
+static void kgsl_sync_callback(struct sync_fence *fence,
+ struct sync_fence_waiter *waiter)
+{
+ struct kgsl_sync_fence_waiter *kwaiter =
+ (struct kgsl_sync_fence_waiter *) waiter;
+ kwaiter->func(kwaiter->priv);
+ sync_fence_put(kwaiter->fence);
+ kfree(kwaiter);
+}
+
+struct kgsl_sync_fence_waiter *kgsl_sync_fence_async_wait(int fd,
+ void (*func)(void *priv), void *priv)
+{
+ struct kgsl_sync_fence_waiter *kwaiter;
+ struct sync_fence *fence;
+ int status;
+
+ fence = sync_fence_fdget(fd);
+ if (fence == NULL)
+ return ERR_PTR(-EINVAL);
+
+ /* create the waiter */
+ kwaiter = kzalloc(sizeof(*kwaiter), GFP_ATOMIC);
+ if (kwaiter == NULL) {
+ sync_fence_put(fence);
+ return ERR_PTR(-ENOMEM);
+ }
+ kwaiter->fence = fence;
+ kwaiter->priv = priv;
+ kwaiter->func = func;
+ sync_fence_waiter_init((struct sync_fence_waiter *) kwaiter,
+ kgsl_sync_callback);
+
+ /* if status then error or signaled */
+ status = sync_fence_wait_async(fence,
+ (struct sync_fence_waiter *) kwaiter);
+ if (status) {
+ kfree(kwaiter);
+ sync_fence_put(fence);
+ if (status < 0)
+ kwaiter = ERR_PTR(status);
+ else
+ kwaiter = NULL;
+ }
+
+ return kwaiter;
+}
+
+int kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_waiter *kwaiter)
+{
+ if (kwaiter == NULL)
+ return 0;
+
+ if (sync_fence_cancel_async(kwaiter->fence,
+ (struct sync_fence_waiter *) kwaiter) == 0) {
+ sync_fence_put(kwaiter->fence);
+ kfree(kwaiter);
+ return 1;
+ }
+ return 0;
+}
diff --git a/drivers/gpu/msm/kgsl_sync.h b/drivers/gpu/msm/kgsl_sync.h
index 63adf06..275eaf0 100644
--- a/drivers/gpu/msm/kgsl_sync.h
+++ b/drivers/gpu/msm/kgsl_sync.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
@@ -28,6 +28,13 @@
unsigned int timestamp;
};
+struct kgsl_sync_fence_waiter {
+ struct sync_fence_waiter waiter;
+ struct sync_fence *fence;
+ void (*func)(void *priv);
+ void *priv;
+};
+
#if defined(CONFIG_SYNC)
struct sync_pt *kgsl_sync_pt_create(struct sync_timeline *timeline,
unsigned int timestamp);
@@ -39,6 +46,9 @@
void kgsl_sync_timeline_signal(struct sync_timeline *timeline,
unsigned int timestamp);
void kgsl_sync_timeline_destroy(struct kgsl_context *context);
+struct kgsl_sync_fence_waiter *kgsl_sync_fence_async_wait(int fd,
+ void (*func)(void *priv), void *priv);
+int kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_waiter *waiter);
#else
static inline struct sync_pt
*kgsl_sync_pt_create(struct sync_timeline *timeline, unsigned int timestamp)
@@ -72,6 +82,20 @@
static inline void kgsl_sync_timeline_destroy(struct kgsl_context *context)
{
}
+
+static inline struct
+kgsl_sync_fence_waiter *kgsl_sync_fence_async_wait(int fd,
+ void (*func)(void *priv), void *priv)
+{
+ return NULL;
+}
+
+static inline int
+kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_waiter *waiter)
+{
+ return 1;
+}
+
#endif
#endif /* __KGSL_SYNC_H */
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 179a72b..5f39b8b 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -730,42 +730,46 @@
);
TRACE_EVENT(kgsl_register_event,
- TP_PROTO(unsigned int id, unsigned int timestamp),
- TP_ARGS(id, timestamp),
+ TP_PROTO(unsigned int id, unsigned int timestamp, void *func),
+ TP_ARGS(id, timestamp, func),
TP_STRUCT__entry(
__field(unsigned int, id)
__field(unsigned int, timestamp)
+ __field(void *, func)
),
TP_fast_assign(
__entry->id = id;
__entry->timestamp = timestamp;
+ __entry->func = func;
),
TP_printk(
- "ctx=%u ts=%u",
- __entry->id, __entry->timestamp)
+ "ctx=%u ts=%u cb=%pF",
+ __entry->id, __entry->timestamp, __entry->func)
);
TRACE_EVENT(kgsl_fire_event,
TP_PROTO(unsigned int id, unsigned int ts,
- unsigned int type, unsigned int age),
- TP_ARGS(id, ts, type, age),
+ unsigned int type, unsigned int age, void *func),
+ TP_ARGS(id, ts, type, age, func),
TP_STRUCT__entry(
__field(unsigned int, id)
__field(unsigned int, ts)
__field(unsigned int, type)
__field(unsigned int, age)
+ __field(void *, func)
),
TP_fast_assign(
__entry->id = id;
__entry->ts = ts;
__entry->type = type;
__entry->age = age;
+ __entry->func = func;
),
TP_printk(
- "ctx=%u ts=%u type=%s age=%u",
+ "ctx=%u ts=%u type=%s age=%u cb=%pF",
__entry->id, __entry->ts,
__print_symbolic(__entry->type, KGSL_EVENT_TYPES),
- __entry->age)
+ __entry->age, __entry->func)
);
TRACE_EVENT(kgsl_active_count,
diff --git a/drivers/gud/mobicore_driver/api.c b/drivers/gud/mobicore_driver/api.c
index 871f6cc..b47383a0 100644
--- a/drivers/gud/mobicore_driver/api.c
+++ b/drivers/gud/mobicore_driver/api.c
@@ -98,7 +98,11 @@
*/
struct mc_instance *mobicore_open(void)
{
- return mc_alloc_instance();
+ struct mc_instance *instance = mc_alloc_instance();
+ if(instance) {
+ instance->admin = true;
+ }
+ return instance;
}
EXPORT_SYMBOL(mobicore_open);
diff --git a/drivers/gud/mobicore_driver/build_tag.h b/drivers/gud/mobicore_driver/build_tag.h
index 2a7772e..4a24275 100644
--- a/drivers/gud/mobicore_driver/build_tag.h
+++ b/drivers/gud/mobicore_driver/build_tag.h
@@ -26,4 +26,4 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define MOBICORE_COMPONENT_BUILD_TAG \
- "*** GC_MSM8960_Release_V019 ###"
+ "*** t-base-202_V001 ###"
diff --git a/drivers/gud/mobicore_driver/main.c b/drivers/gud/mobicore_driver/main.c
index 6f91974..0451452 100644
--- a/drivers/gud/mobicore_driver/main.c
+++ b/drivers/gud/mobicore_driver/main.c
@@ -47,7 +47,7 @@
/* Define a MobiCore device structure for use with dev_debug() etc */
struct device_driver mcd_debug_name = {
- .name = "mcdrvkmod"
+ .name = "MobiCore"
};
struct device mcd_debug_subname = {
diff --git a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h b/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
index 4768f39..7854fc5 100644
--- a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
+++ b/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
@@ -41,7 +41,15 @@
/* Enable the use of vm_unamp instead of the deprecated do_munmap
* and other 3.7 features
*/
+#ifndef CONFIG_ARCH_MSM8960
#define MC_VM_UNMAP
+#endif
+
+
+#if defined(CONFIG_ARCH_MSM8974) || defined(CONFIG_ARCH_MSM8226)
+/* Perform clock enable/disable */
+#define MC_CRYPTO_CLOCK_MANAGEMENT
+#endif
/* Enable Power Management for Crypto Engine */
#define MC_CRYPTO_CLOCK_MANAGEMENT
diff --git a/drivers/gud/mobicore_driver/pm.c b/drivers/gud/mobicore_driver/pm.c
index 3ad2015..55a1ef7 100644
--- a/drivers/gud/mobicore_driver/pm.c
+++ b/drivers/gud/mobicore_driver/pm.c
@@ -67,8 +67,8 @@
MCDRV_DBG(mcd, "MobiCore IDLE=%d!", flags->schedule);
MCDRV_DBG(mcd,
"MobiCore Request Sleep=%d!", flags->sleep_mode.SleepReq);
- MCDRV_DBG(mcd, "MobiCore Sleep Ready=%d!",
- flags->sleep_mode.ReadyToSleep);
+ MCDRV_DBG(mcd,
+ "MobiCore Sleep Ready=%d!", flags->sleep_mode.ReadyToSleep);
}
static int mc_suspend_notifier(struct notifier_block *nb,
diff --git a/drivers/gud/mobicore_driver/public/mc_linux.h b/drivers/gud/mobicore_driver/public/mc_linux.h
index 9c49aef..af027dc 100644
--- a/drivers/gud/mobicore_driver/public/mc_linux.h
+++ b/drivers/gud/mobicore_driver/public/mc_linux.h
@@ -43,6 +43,10 @@
#include "version.h"
+#ifndef __KERNEL__
+#include <stdint.h>
+#endif
+
#define MC_ADMIN_DEVNODE "mobicore"
#define MC_USER_DEVNODE "mobicore-user"
diff --git a/drivers/gud/mobicore_kernelapi/clientlib.c b/drivers/gud/mobicore_kernelapi/clientlib.c
index 7038e02..16b52e5 100644
--- a/drivers/gud/mobicore_kernelapi/clientlib.c
+++ b/drivers/gud/mobicore_kernelapi/clientlib.c
@@ -299,7 +299,8 @@
{
session->device_id,
*uuid,
- (uint32_t)wsm->phys_addr,
+ (uint32_t)(wsm->phys_addr) & 0xFFF,
+ wsm->handle,
len
}
};
@@ -926,7 +927,8 @@
{
session->session_id,
handle,
- (uint32_t)(map_info->secure_virt_addr)
+ (uint32_t)(map_info->secure_virt_addr),
+ map_info->secure_virt_len
}
};
@@ -956,11 +958,11 @@
break;
}
- struct mc_drv_rsp_unmap_bulk_mem_payload_t
+ /*struct mc_drv_rsp_unmap_bulk_mem_payload_t
rsp_unmap_bulk_mem_payload;
connection_read_datablock(dev_con,
&rsp_unmap_bulk_mem_payload,
- sizeof(rsp_unmap_bulk_mem_payload));
+ sizeof(rsp_unmap_bulk_mem_payload));*/
/*
* Unregister mapped bulk buffer from Kernel Module and
diff --git a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h
index 3b8eb4b..eaf7e6c 100644
--- a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h
+++ b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h
@@ -109,6 +109,7 @@
uint32_t device_id;
struct mc_uuid_t uuid;
uint32_t tci;
+ uint32_t handle;
uint32_t len;
};
@@ -119,10 +120,8 @@
struct mc_drv_rsp_open_session_payload_t {
- uint32_t device_id;
uint32_t session_id;
uint32_t device_session_id;
- uint32_t mc_result;
uint32_t session_magic;
};
@@ -186,7 +185,6 @@
struct mc_drv_rsp_map_bulk_mem_payload_t {
uint32_t session_id;
uint32_t secure_virtual_adr;
- uint32_t mc_result;
};
struct mc_drv_rsp_map_bulk_mem_t {
@@ -210,7 +208,6 @@
struct mc_drv_rsp_unmap_bulk_mem_payload_t {
uint32_t response_id;
uint32_t session_id;
- uint32_t mc_result;
};
struct mc_drv_rsp_unmap_bulk_mem_t {
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index 4e77ca2..8b0fcf4 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -377,7 +377,8 @@
return adc_voltage;
}
-int32_t qpnp_adc_scale_pmic_therm(int32_t adc_code,
+int32_t qpnp_adc_scale_pmic_therm(struct qpnp_vadc_chip *vadc,
+ int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
const struct qpnp_vadc_chan_properties *chan_properties,
struct qpnp_vadc_result *adc_chan_result)
@@ -421,7 +422,7 @@
}
EXPORT_SYMBOL(qpnp_adc_scale_pmic_therm);
-int32_t qpnp_adc_scale_millidegc_pmic_voltage_thr(
+int32_t qpnp_adc_scale_millidegc_pmic_voltage_thr(struct qpnp_vadc_chip *chip,
struct qpnp_adc_tm_btm_param *param,
uint32_t *low_threshold, uint32_t *high_threshold)
{
@@ -429,7 +430,7 @@
int64_t low_output = 0, high_output = 0;
int rc = 0, sign = 0;
- rc = qpnp_get_vadc_gain_and_offset(&btm_param, CALIB_ABSOLUTE);
+ rc = qpnp_get_vadc_gain_and_offset(chip, &btm_param, CALIB_ABSOLUTE);
if (rc < 0) {
pr_err("Could not acquire gain and offset\n");
return rc;
@@ -476,7 +477,8 @@
/* Scales the ADC code to degC using the mapping
* table for the XO thermistor.
*/
-int32_t qpnp_adc_tdkntcg_therm(int32_t adc_code,
+int32_t qpnp_adc_tdkntcg_therm(struct qpnp_vadc_chip *chip,
+ int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
const struct qpnp_vadc_chan_properties *chan_properties,
struct qpnp_vadc_result *adc_chan_result)
@@ -499,7 +501,8 @@
}
EXPORT_SYMBOL(qpnp_adc_tdkntcg_therm);
-int32_t qpnp_adc_scale_batt_therm(int32_t adc_code,
+int32_t qpnp_adc_scale_batt_therm(struct qpnp_vadc_chip *chip,
+ int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
const struct qpnp_vadc_chan_properties *chan_properties,
struct qpnp_vadc_result *adc_chan_result)
@@ -517,7 +520,8 @@
}
EXPORT_SYMBOL(qpnp_adc_scale_batt_therm);
-int32_t qpnp_adc_scale_qrd_batt_therm(int32_t adc_code,
+int32_t qpnp_adc_scale_qrd_batt_therm(struct qpnp_vadc_chip *chip,
+ int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
const struct qpnp_vadc_chan_properties *chan_properties,
struct qpnp_vadc_result *adc_chan_result)
@@ -535,7 +539,8 @@
}
EXPORT_SYMBOL(qpnp_adc_scale_qrd_batt_therm);
-int32_t qpnp_adc_scale_therm_pu1(int32_t adc_code,
+int32_t qpnp_adc_scale_therm_pu1(struct qpnp_vadc_chip *chip,
+ int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
const struct qpnp_vadc_chan_properties *chan_properties,
struct qpnp_vadc_result *adc_chan_result)
@@ -553,7 +558,8 @@
}
EXPORT_SYMBOL(qpnp_adc_scale_therm_pu1);
-int32_t qpnp_adc_scale_therm_pu2(int32_t adc_code,
+int32_t qpnp_adc_scale_therm_pu2(struct qpnp_vadc_chip *chip,
+ int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
const struct qpnp_vadc_chan_properties *chan_properties,
struct qpnp_vadc_result *adc_chan_result)
@@ -571,13 +577,14 @@
}
EXPORT_SYMBOL(qpnp_adc_scale_therm_pu2);
-int32_t qpnp_adc_tm_scale_voltage_therm_pu2(uint32_t reg, int64_t *result)
+int32_t qpnp_adc_tm_scale_voltage_therm_pu2(struct qpnp_vadc_chip *chip,
+ uint32_t reg, int64_t *result)
{
int64_t adc_voltage = 0;
struct qpnp_vadc_linear_graph param1;
int negative_offset;
- qpnp_get_vadc_gain_and_offset(¶m1, CALIB_RATIOMETRIC);
+ qpnp_get_vadc_gain_and_offset(chip, ¶m1, CALIB_RATIOMETRIC);
adc_voltage = (reg - param1.adc_gnd) * param1.adc_vref;
if (adc_voltage < 0) {
@@ -597,12 +604,13 @@
}
EXPORT_SYMBOL(qpnp_adc_tm_scale_voltage_therm_pu2);
-int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_adc_tm_config *param)
+int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_vadc_chip *chip,
+ struct qpnp_adc_tm_config *param)
{
struct qpnp_vadc_linear_graph param1;
int rc;
- qpnp_get_vadc_gain_and_offset(¶m1, CALIB_RATIOMETRIC);
+ qpnp_get_vadc_gain_and_offset(chip, ¶m1, CALIB_RATIOMETRIC);
rc = qpnp_adc_map_temp_voltage(adcmap_100k_104ef_104fb,
ARRAY_SIZE(adcmap_100k_104ef_104fb),
@@ -628,7 +636,8 @@
}
EXPORT_SYMBOL(qpnp_adc_tm_scale_therm_voltage_pu2);
-int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
+int32_t qpnp_adc_scale_batt_id(struct qpnp_vadc_chip *chip,
+ int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
const struct qpnp_vadc_chan_properties *chan_properties,
struct qpnp_vadc_result *adc_chan_result)
@@ -644,7 +653,8 @@
}
EXPORT_SYMBOL(qpnp_adc_scale_batt_id);
-int32_t qpnp_adc_scale_default(int32_t adc_code,
+int32_t qpnp_adc_scale_default(struct qpnp_vadc_chip *vadc,
+ int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
const struct qpnp_vadc_chan_properties *chan_properties,
struct qpnp_vadc_result *adc_chan_result)
@@ -701,12 +711,13 @@
}
EXPORT_SYMBOL(qpnp_adc_scale_default);
-int32_t qpnp_adc_usb_scaler(struct qpnp_adc_tm_btm_param *param,
+int32_t qpnp_adc_usb_scaler(struct qpnp_vadc_chip *chip,
+ struct qpnp_adc_tm_btm_param *param,
uint32_t *low_threshold, uint32_t *high_threshold)
{
struct qpnp_vadc_linear_graph usb_param;
- qpnp_get_vadc_gain_and_offset(&usb_param, CALIB_RATIOMETRIC);
+ qpnp_get_vadc_gain_and_offset(chip, &usb_param, CALIB_RATIOMETRIC);
*low_threshold = param->low_thr * usb_param.dy;
do_div(*low_threshold, usb_param.adc_vref);
@@ -722,14 +733,15 @@
}
EXPORT_SYMBOL(qpnp_adc_usb_scaler);
-int32_t qpnp_adc_vbatt_rscaler(struct qpnp_adc_tm_btm_param *param,
+int32_t qpnp_adc_vbatt_rscaler(struct qpnp_vadc_chip *chip,
+ struct qpnp_adc_tm_btm_param *param,
uint32_t *low_threshold, uint32_t *high_threshold)
{
struct qpnp_vadc_linear_graph vbatt_param;
int rc = 0, sign = 0;
int64_t low_thr = 0, high_thr = 0;
- rc = qpnp_get_vadc_gain_and_offset(&vbatt_param, CALIB_ABSOLUTE);
+ rc = qpnp_get_vadc_gain_and_offset(chip, &vbatt_param, CALIB_ABSOLUTE);
if (rc < 0)
return rc;
@@ -764,14 +776,15 @@
}
EXPORT_SYMBOL(qpnp_adc_vbatt_rscaler);
-int32_t qpnp_adc_btm_scaler(struct qpnp_adc_tm_btm_param *param,
+int32_t qpnp_adc_btm_scaler(struct qpnp_vadc_chip *chip,
+ struct qpnp_adc_tm_btm_param *param,
uint32_t *low_threshold, uint32_t *high_threshold)
{
struct qpnp_vadc_linear_graph btm_param;
int64_t low_output = 0, high_output = 0;
int rc = 0;
- qpnp_get_vadc_gain_and_offset(&btm_param, CALIB_RATIOMETRIC);
+ qpnp_get_vadc_gain_and_offset(chip, &btm_param, CALIB_RATIOMETRIC);
pr_debug("warm_temp:%d and cool_temp:%d\n", param->high_temp,
param->low_temp);
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index a453159..8e6afc1 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -134,26 +134,28 @@
u8 revision;
};
-struct qpnp_iadc_drv {
+struct qpnp_iadc_chip {
struct qpnp_adc_drv *adc;
int32_t rsense;
bool external_rsense;
struct device *iadc_hwmon;
- bool iadc_initialized;
+ struct list_head list;
int64_t die_temp;
struct delayed_work iadc_work;
struct mutex iadc_vadc_lock;
bool iadc_mode_sel;
struct qpnp_iadc_comp iadc_comp;
+ struct qpnp_vadc_chip *vadc_dev;
+ struct work_struct trigger_completion_work;
struct sensor_device_attribute sens_attr[0];
bool skip_auto_calibrations;
};
-static struct qpnp_iadc_drv *qpnp_iadc;
+LIST_HEAD(qpnp_iadc_device_list);
-static int32_t qpnp_iadc_read_reg(uint32_t reg, u8 *data)
+static int32_t qpnp_iadc_read_reg(struct qpnp_iadc_chip *iadc,
+ uint32_t reg, u8 *data)
{
- struct qpnp_iadc_drv *iadc = qpnp_iadc;
int rc;
rc = spmi_ext_register_readl(iadc->adc->spmi->ctrl, iadc->adc->slave,
@@ -166,9 +168,9 @@
return 0;
}
-static int32_t qpnp_iadc_write_reg(uint32_t reg, u8 data)
+static int32_t qpnp_iadc_write_reg(struct qpnp_iadc_chip *iadc,
+ uint32_t reg, u8 data)
{
- struct qpnp_iadc_drv *iadc = qpnp_iadc;
int rc;
u8 *buf;
@@ -183,41 +185,54 @@
return 0;
}
-static void trigger_iadc_completion(struct work_struct *work)
+static int qpnp_iadc_is_valid(struct qpnp_iadc_chip *iadc)
{
- struct qpnp_iadc_drv *iadc = qpnp_iadc;
+ struct qpnp_iadc_chip *iadc_chip = NULL;
- if (!iadc || !iadc->iadc_initialized)
+ list_for_each_entry(iadc_chip, &qpnp_iadc_device_list, list)
+ if (iadc == iadc_chip)
+ return 0;
+
+ return -EINVAL;
+}
+
+static void qpnp_iadc_trigger_completion(struct work_struct *work)
+{
+ struct qpnp_iadc_chip *iadc = container_of(work,
+ struct qpnp_iadc_chip, trigger_completion_work);
+
+ if (qpnp_iadc_is_valid(iadc) < 0)
return;
complete(&iadc->adc->adc_rslt_completion);
return;
}
-DECLARE_WORK(trigger_iadc_completion_work, trigger_iadc_completion);
static irqreturn_t qpnp_iadc_isr(int irq, void *dev_id)
{
- schedule_work(&trigger_iadc_completion_work);
+ struct qpnp_iadc_chip *iadc = dev_id;
+
+ schedule_work(&iadc->trigger_completion_work);
return IRQ_HANDLED;
}
-static int32_t qpnp_iadc_enable(bool state)
+static int32_t qpnp_iadc_enable(struct qpnp_iadc_chip *dev, bool state)
{
int rc = 0;
u8 data = 0;
data = QPNP_IADC_ADC_EN;
if (state) {
- rc = qpnp_iadc_write_reg(QPNP_IADC_EN_CTL1,
+ rc = qpnp_iadc_write_reg(dev, QPNP_IADC_EN_CTL1,
data);
if (rc < 0) {
pr_err("IADC enable failed\n");
return rc;
}
} else {
- rc = qpnp_iadc_write_reg(QPNP_IADC_EN_CTL1,
+ rc = qpnp_iadc_write_reg(dev, QPNP_IADC_EN_CTL1,
(~data & QPNP_IADC_ADC_EN));
if (rc < 0) {
pr_err("IADC disable failed\n");
@@ -228,36 +243,36 @@
return 0;
}
-static int32_t qpnp_iadc_status_debug(void)
+static int32_t qpnp_iadc_status_debug(struct qpnp_iadc_chip *dev)
{
int rc = 0;
u8 mode = 0, status1 = 0, chan = 0, dig = 0, en = 0;
- rc = qpnp_iadc_read_reg(QPNP_IADC_MODE_CTL, &mode);
+ rc = qpnp_iadc_read_reg(dev, QPNP_IADC_MODE_CTL, &mode);
if (rc < 0) {
pr_err("mode ctl register read failed with %d\n", rc);
return rc;
}
- rc = qpnp_iadc_read_reg(QPNP_ADC_DIG_PARAM, &dig);
+ rc = qpnp_iadc_read_reg(dev, QPNP_ADC_DIG_PARAM, &dig);
if (rc < 0) {
pr_err("digital param read failed with %d\n", rc);
return rc;
}
- rc = qpnp_iadc_read_reg(QPNP_IADC_ADC_CH_SEL_CTL, &chan);
+ rc = qpnp_iadc_read_reg(dev, QPNP_IADC_ADC_CH_SEL_CTL, &chan);
if (rc < 0) {
pr_err("channel read failed with %d\n", rc);
return rc;
}
- rc = qpnp_iadc_read_reg(QPNP_STATUS1, &status1);
+ rc = qpnp_iadc_read_reg(dev, QPNP_STATUS1, &status1);
if (rc < 0) {
pr_err("status1 read failed with %d\n", rc);
return rc;
}
- rc = qpnp_iadc_read_reg(QPNP_IADC_EN_CTL1, &en);
+ rc = qpnp_iadc_read_reg(dev, QPNP_IADC_EN_CTL1, &en);
if (rc < 0) {
pr_err("en read failed with %d\n", rc);
return rc;
@@ -266,7 +281,7 @@
pr_debug("EOC not set with status:%x, dig:%x, ch:%x, mode:%x, en:%x\n",
status1, dig, chan, mode, en);
- rc = qpnp_iadc_enable(false);
+ rc = qpnp_iadc_enable(dev, false);
if (rc < 0) {
pr_err("IADC disable failed with %d\n", rc);
return rc;
@@ -275,19 +290,20 @@
return 0;
}
-static int32_t qpnp_iadc_read_conversion_result(uint16_t *data)
+static int32_t qpnp_iadc_read_conversion_result(struct qpnp_iadc_chip *iadc,
+ int16_t *data)
{
uint8_t rslt_lsb, rslt_msb;
uint16_t rslt;
int32_t rc;
- rc = qpnp_iadc_read_reg(QPNP_IADC_DATA0, &rslt_lsb);
+ rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_DATA0, &rslt_lsb);
if (rc < 0) {
pr_err("qpnp adc result read failed with %d\n", rc);
return rc;
}
- rc = qpnp_iadc_read_reg(QPNP_IADC_DATA1, &rslt_msb);
+ rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_DATA1, &rslt_msb);
if (rc < 0) {
pr_err("qpnp adc result read failed with %d\n", rc);
return rc;
@@ -296,7 +312,7 @@
rslt = (rslt_msb << 8) | rslt_lsb;
*data = rslt;
- rc = qpnp_iadc_enable(false);
+ rc = qpnp_iadc_enable(iadc, false);
if (rc)
return rc;
@@ -363,32 +379,30 @@
return 0;
}
-int32_t qpnp_iadc_comp_result(int64_t *result)
+int32_t qpnp_iadc_comp_result(struct qpnp_iadc_chip *iadc, int64_t *result)
{
- struct qpnp_iadc_drv *iadc = qpnp_iadc;
-
return qpnp_iadc_comp(result, iadc->iadc_comp, iadc->die_temp);
}
EXPORT_SYMBOL(qpnp_iadc_comp_result);
-static int32_t qpnp_iadc_comp_info(void)
+static int32_t qpnp_iadc_comp_info(struct qpnp_iadc_chip *iadc)
{
- struct qpnp_iadc_drv *iadc = qpnp_iadc;
int rc = 0;
- rc = qpnp_iadc_read_reg(QPNP_INT_TEST_VAL, &iadc->iadc_comp.id);
+ rc = qpnp_iadc_read_reg(iadc, QPNP_INT_TEST_VAL, &iadc->iadc_comp.id);
if (rc < 0) {
pr_err("qpnp adc comp id failed with %d\n", rc);
return rc;
}
- rc = qpnp_iadc_read_reg(QPNP_IADC_REVISION2, &iadc->iadc_comp.revision);
+ rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION2,
+ &iadc->iadc_comp.revision);
if (rc < 0) {
pr_err("qpnp adc revision read failed with %d\n", rc);
return rc;
}
- rc = qpnp_iadc_read_reg(QPNP_IADC_ATE_GAIN_CALIB_OFFSET,
+ rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_ATE_GAIN_CALIB_OFFSET,
&iadc->iadc_comp.sys_gain);
if (rc < 0) {
pr_err("full scale read failed with %d\n", rc);
@@ -406,10 +420,10 @@
return rc;
}
-static int32_t qpnp_iadc_configure(enum qpnp_iadc_channels channel,
+static int32_t qpnp_iadc_configure(struct qpnp_iadc_chip *iadc,
+ enum qpnp_iadc_channels channel,
uint16_t *raw_code, uint32_t mode_sel)
{
- struct qpnp_iadc_drv *iadc = qpnp_iadc;
u8 qpnp_iadc_mode_reg = 0, qpnp_iadc_ch_sel_reg = 0;
u8 qpnp_iadc_conv_req = 0, qpnp_iadc_dig_param_reg = 0;
int32_t rc = 0;
@@ -425,34 +439,34 @@
qpnp_iadc_conv_req = QPNP_IADC_CONV_REQ;
- rc = qpnp_iadc_write_reg(QPNP_IADC_MODE_CTL, qpnp_iadc_mode_reg);
+ rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_MODE_CTL, qpnp_iadc_mode_reg);
if (rc) {
pr_err("qpnp adc read adc failed with %d\n", rc);
return rc;
}
- rc = qpnp_iadc_write_reg(QPNP_IADC_ADC_CH_SEL_CTL,
+ rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_ADC_CH_SEL_CTL,
qpnp_iadc_ch_sel_reg);
if (rc) {
pr_err("qpnp adc read adc failed with %d\n", rc);
return rc;
}
- rc = qpnp_iadc_write_reg(QPNP_ADC_DIG_PARAM,
+ rc = qpnp_iadc_write_reg(iadc, QPNP_ADC_DIG_PARAM,
qpnp_iadc_dig_param_reg);
if (rc) {
pr_err("qpnp adc read adc failed with %d\n", rc);
return rc;
}
- rc = qpnp_iadc_write_reg(QPNP_HW_SETTLE_DELAY,
+ rc = qpnp_iadc_write_reg(iadc, QPNP_HW_SETTLE_DELAY,
iadc->adc->amux_prop->hw_settle_time);
if (rc < 0) {
pr_err("qpnp adc configure error for hw settling time setup\n");
return rc;
}
- rc = qpnp_iadc_write_reg(QPNP_FAST_AVG_CTL,
+ rc = qpnp_iadc_write_reg(iadc, QPNP_FAST_AVG_CTL,
iadc->adc->amux_prop->fast_avg_setup);
if (rc < 0) {
pr_err("qpnp adc fast averaging configure error\n");
@@ -461,11 +475,11 @@
INIT_COMPLETION(iadc->adc->adc_rslt_completion);
- rc = qpnp_iadc_enable(true);
+ rc = qpnp_iadc_enable(iadc, true);
if (rc)
return rc;
- rc = qpnp_iadc_write_reg(QPNP_CONV_REQ, qpnp_iadc_conv_req);
+ rc = qpnp_iadc_write_reg(iadc, QPNP_CONV_REQ, qpnp_iadc_conv_req);
if (rc) {
pr_err("qpnp adc read adc failed with %d\n", rc);
return rc;
@@ -475,14 +489,14 @@
QPNP_ADC_COMPLETION_TIMEOUT);
if (!rc) {
u8 status1 = 0;
- rc = qpnp_iadc_read_reg(QPNP_STATUS1, &status1);
+ rc = qpnp_iadc_read_reg(iadc, QPNP_STATUS1, &status1);
if (rc < 0)
return rc;
status1 &= (QPNP_STATUS1_REQ_STS | QPNP_STATUS1_EOC);
if (status1 == QPNP_STATUS1_EOC)
pr_debug("End of conversion status set\n");
else {
- rc = qpnp_iadc_status_debug();
+ rc = qpnp_iadc_status_debug(iadc);
if (rc < 0) {
pr_err("status1 read failed with %d\n", rc);
return rc;
@@ -491,7 +505,7 @@
}
}
- rc = qpnp_iadc_read_conversion_result(raw_code);
+ rc = qpnp_iadc_read_conversion_result(iadc, raw_code);
if (rc) {
pr_err("qpnp adc read adc failed with %d\n", rc);
return rc;
@@ -503,9 +517,8 @@
#define IADC_CENTER 0xC000
#define IADC_READING_RESOLUTION_N 542535
#define IADC_READING_RESOLUTION_D 100000
-static int32_t qpnp_convert_raw_offset_voltage(void)
+static int32_t qpnp_convert_raw_offset_voltage(struct qpnp_iadc_chip *iadc)
{
- struct qpnp_iadc_drv *iadc = qpnp_iadc;
s64 numerator;
if ((iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw) == 0) {
@@ -530,20 +543,20 @@
return 0;
}
-int32_t qpnp_iadc_calibrate_for_trim(bool batfet_closed)
+int32_t qpnp_iadc_calibrate_for_trim(struct qpnp_iadc_chip *iadc,
+ bool batfet_closed)
{
- struct qpnp_iadc_drv *iadc = qpnp_iadc;
uint8_t rslt_lsb, rslt_msb;
int32_t rc = 0;
uint16_t raw_data;
uint32_t mode_sel = 0;
- if (!iadc || !iadc->iadc_initialized)
+ if (qpnp_iadc_is_valid(iadc) < 0)
return -EPROBE_DEFER;
mutex_lock(&iadc->adc->adc_lock);
- rc = qpnp_iadc_configure(GAIN_CALIBRATION_17P857MV,
+ rc = qpnp_iadc_configure(iadc, GAIN_CALIBRATION_17P857MV,
&raw_data, mode_sel);
if (rc < 0) {
pr_err("qpnp adc result read failed with %d\n", rc);
@@ -561,7 +574,7 @@
*/
if (!batfet_closed || iadc->external_rsense) {
/* external offset calculation */
- rc = qpnp_iadc_configure(OFFSET_CALIBRATION_CSP_CSN,
+ rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP_CSN,
&raw_data, mode_sel);
if (rc < 0) {
pr_err("qpnp adc result read failed with %d\n", rc);
@@ -569,7 +582,7 @@
}
} else {
/* internal offset calculation */
- rc = qpnp_iadc_configure(OFFSET_CALIBRATION_CSP2_CSN2,
+ rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP2_CSN2,
&raw_data, mode_sel);
if (rc < 0) {
pr_err("qpnp adc result read failed with %d\n", rc);
@@ -586,7 +599,7 @@
pr_debug("raw gain:0x%x, raw offset:0x%x\n",
iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw);
- rc = qpnp_convert_raw_offset_voltage();
+ rc = qpnp_convert_raw_offset_voltage(iadc);
if (rc < 0) {
pr_err("qpnp raw_voltage conversion failed\n");
goto fail;
@@ -598,28 +611,28 @@
pr_debug("trim values:lsb:0x%x and msb:0x%x\n", rslt_lsb, rslt_msb);
- rc = qpnp_iadc_write_reg(QPNP_IADC_SEC_ACCESS,
+ rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_SEC_ACCESS,
QPNP_IADC_SEC_ACCESS_DATA);
if (rc < 0) {
pr_err("qpnp iadc configure error for sec access\n");
goto fail;
}
- rc = qpnp_iadc_write_reg(QPNP_IADC_MSB_OFFSET,
+ rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_MSB_OFFSET,
rslt_msb);
if (rc < 0) {
pr_err("qpnp iadc configure error for MSB write\n");
goto fail;
}
- rc = qpnp_iadc_write_reg(QPNP_IADC_SEC_ACCESS,
+ rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_SEC_ACCESS,
QPNP_IADC_SEC_ACCESS_DATA);
if (rc < 0) {
pr_err("qpnp iadc configure error for sec access\n");
goto fail;
}
- rc = qpnp_iadc_write_reg(QPNP_IADC_LSB_OFFSET,
+ rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_LSB_OFFSET,
rslt_lsb);
if (rc < 0) {
pr_err("qpnp iadc configure error for LSB write\n");
@@ -633,11 +646,12 @@
static void qpnp_iadc_work(struct work_struct *work)
{
- struct qpnp_iadc_drv *iadc = qpnp_iadc;
+ struct qpnp_iadc_chip *iadc = container_of(work,
+ struct qpnp_iadc_chip, iadc_work.work);
int rc = 0;
if (!iadc->skip_auto_calibrations) {
- rc = qpnp_iadc_calibrate_for_trim(true);
+ rc = qpnp_iadc_calibrate_for_trim(iadc, true);
if (rc)
pr_debug("periodic IADC calibration failed\n");
}
@@ -648,12 +662,12 @@
return;
}
-static int32_t qpnp_iadc_version_check(void)
+static int32_t qpnp_iadc_version_check(struct qpnp_iadc_chip *iadc)
{
uint8_t revision;
int rc;
- rc = qpnp_iadc_read_reg(QPNP_IADC_REVISION2, &revision);
+ rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION2, &revision);
if (rc < 0) {
pr_err("qpnp adc result read failed with %d\n", rc);
return rc;
@@ -667,24 +681,31 @@
return 0;
}
-int32_t qpnp_iadc_is_ready(void)
+struct qpnp_iadc_chip *qpnp_get_iadc(struct device *dev, const char *name)
{
- struct qpnp_iadc_drv *iadc = qpnp_iadc;
+ struct qpnp_iadc_chip *iadc;
+ struct device_node *node = NULL;
+ char prop_name[QPNP_MAX_PROP_NAME_LEN];
- if (!iadc || !iadc->iadc_initialized)
- return -EPROBE_DEFER;
- else
- return 0;
+ snprintf(prop_name, QPNP_MAX_PROP_NAME_LEN, "qcom,%s-iadc", name);
+
+ node = of_parse_phandle(dev->of_node, prop_name, 0);
+ if (node == NULL)
+ return ERR_PTR(-ENODEV);
+
+ list_for_each_entry(iadc, &qpnp_iadc_device_list, list)
+ if (iadc->adc->spmi->dev.of_node == node)
+ return iadc;
+ return ERR_PTR(-EPROBE_DEFER);
}
-EXPORT_SYMBOL(qpnp_iadc_is_ready);
+EXPORT_SYMBOL(qpnp_get_iadc);
-int32_t qpnp_iadc_get_rsense(int32_t *rsense)
+int32_t qpnp_iadc_get_rsense(struct qpnp_iadc_chip *iadc, int32_t *rsense)
{
- struct qpnp_iadc_drv *iadc = qpnp_iadc;
uint8_t rslt_rsense;
int32_t rc = 0, sign_bit = 0;
- if (!iadc || !iadc->iadc_initialized)
+ if (qpnp_iadc_is_valid(iadc) < 0)
return -EPROBE_DEFER;
if (iadc->external_rsense) {
@@ -692,7 +713,7 @@
return rc;
}
- rc = qpnp_iadc_read_reg(QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense);
+ rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense);
if (rc < 0) {
pr_err("qpnp adc rsense read failed with %d\n", rc);
return rc;
@@ -716,14 +737,13 @@
}
EXPORT_SYMBOL(qpnp_iadc_get_rsense);
-static int32_t qpnp_check_pmic_temp(void)
+static int32_t qpnp_check_pmic_temp(struct qpnp_iadc_chip *iadc)
{
- struct qpnp_iadc_drv *iadc = qpnp_iadc;
struct qpnp_vadc_result result_pmic_therm;
int64_t die_temp_offset;
int rc = 0;
- rc = qpnp_vadc_read(DIE_TEMP, &result_pmic_therm);
+ rc = qpnp_vadc_read(iadc->vadc_dev, DIE_TEMP, &result_pmic_therm);
if (rc < 0)
return rc;
@@ -735,7 +755,7 @@
if (die_temp_offset > QPNP_IADC_DIE_TEMP_CALIB_OFFSET) {
iadc->die_temp = result_pmic_therm.physical;
if (!iadc->skip_auto_calibrations) {
- rc = qpnp_iadc_calibrate_for_trim(true);
+ rc = qpnp_iadc_calibrate_for_trim(iadc, true);
if (rc)
pr_err("IADC calibration failed rc = %d\n", rc);
}
@@ -744,20 +764,20 @@
return rc;
}
-int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
+int32_t qpnp_iadc_read(struct qpnp_iadc_chip *iadc,
+ enum qpnp_iadc_channels channel,
struct qpnp_iadc_result *result)
{
- struct qpnp_iadc_drv *iadc = qpnp_iadc;
int32_t rc, rsense_n_ohms, sign = 0, num, mode_sel = 0;
int32_t rsense_u_ohms = 0;
int64_t result_current;
uint16_t raw_data;
- if (!iadc || !iadc->iadc_initialized)
+ if (qpnp_iadc_is_valid(iadc) < 0)
return -EPROBE_DEFER;
if (!iadc->iadc_mode_sel) {
- rc = qpnp_check_pmic_temp();
+ rc = qpnp_check_pmic_temp(iadc);
if (rc) {
pr_err("Error checking pmic therm temp\n");
return rc;
@@ -766,13 +786,13 @@
mutex_lock(&iadc->adc->adc_lock);
- rc = qpnp_iadc_configure(channel, &raw_data, mode_sel);
+ rc = qpnp_iadc_configure(iadc, channel, &raw_data, mode_sel);
if (rc < 0) {
pr_err("qpnp adc result read failed with %d\n", rc);
goto fail;
}
- rc = qpnp_iadc_get_rsense(&rsense_n_ohms);
+ rc = qpnp_iadc_get_rsense(iadc, &rsense_n_ohms);
pr_debug("current raw:0%x and rsense:%d\n",
raw_data, rsense_n_ohms);
rsense_u_ohms = rsense_n_ohms/1000;
@@ -793,7 +813,7 @@
result->result_uv = -result->result_uv;
result_current = -result_current;
}
- rc = qpnp_iadc_comp_result(&result_current);
+ rc = qpnp_iadc_comp_result(iadc, &result_current);
if (rc < 0)
pr_err("Error during compensating the IADC\n");
rc = 0;
@@ -806,15 +826,15 @@
}
EXPORT_SYMBOL(qpnp_iadc_read);
-int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_calib *result)
+int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_chip *iadc,
+ struct qpnp_iadc_calib *result)
{
- struct qpnp_iadc_drv *iadc = qpnp_iadc;
int rc;
- if (!iadc || !iadc->iadc_initialized)
+ if (qpnp_iadc_is_valid(iadc) < 0)
return -EPROBE_DEFER;
- rc = qpnp_check_pmic_temp();
+ rc = qpnp_check_pmic_temp(iadc);
if (rc) {
pr_err("Error checking pmic therm temp\n");
return rc;
@@ -838,43 +858,32 @@
}
EXPORT_SYMBOL(qpnp_iadc_get_gain_and_offset);
-int qpnp_iadc_skip_calibration(void)
+int qpnp_iadc_skip_calibration(struct qpnp_iadc_chip *iadc)
{
- struct qpnp_iadc_drv *iadc = qpnp_iadc;
-
- if (!iadc || !iadc->iadc_initialized)
- return -EPROBE_DEFER;
-
iadc->skip_auto_calibrations = true;
return 0;
}
EXPORT_SYMBOL(qpnp_iadc_skip_calibration);
-int qpnp_iadc_resume_calibration(void)
+int qpnp_iadc_resume_calibration(struct qpnp_iadc_chip *iadc)
{
- struct qpnp_iadc_drv *iadc = qpnp_iadc;
-
- if (!iadc || !iadc->iadc_initialized)
- return -EPROBE_DEFER;
-
iadc->skip_auto_calibrations = false;
return 0;
}
EXPORT_SYMBOL(qpnp_iadc_resume_calibration);
-int32_t qpnp_iadc_vadc_sync_read(
+int32_t qpnp_iadc_vadc_sync_read(struct qpnp_iadc_chip *iadc,
enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result)
{
- struct qpnp_iadc_drv *iadc = qpnp_iadc;
int rc = 0;
- if (!iadc || !iadc->iadc_initialized)
+ if (qpnp_iadc_is_valid(iadc) < 0)
return -EPROBE_DEFER;
mutex_lock(&iadc->iadc_vadc_lock);
- rc = qpnp_check_pmic_temp();
+ rc = qpnp_check_pmic_temp(iadc);
if (rc) {
pr_err("PMIC die temp check failed\n");
goto fail;
@@ -882,18 +891,18 @@
iadc->iadc_mode_sel = true;
- rc = qpnp_vadc_iadc_sync_request(v_channel);
+ rc = qpnp_vadc_iadc_sync_request(iadc->vadc_dev, v_channel);
if (rc) {
pr_err("Configuring VADC failed\n");
goto fail;
}
- rc = qpnp_iadc_read(i_channel, i_result);
+ rc = qpnp_iadc_read(iadc, i_channel, i_result);
if (rc)
pr_err("Configuring IADC failed\n");
/* Intentional fall through to release VADC */
- rc = qpnp_vadc_iadc_sync_complete_request(v_channel,
+ rc = qpnp_vadc_iadc_sync_complete_request(iadc->vadc_dev, v_channel,
v_result);
if (rc)
pr_err("Releasing VADC failed\n");
@@ -910,10 +919,11 @@
struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct qpnp_iadc_chip *iadc = dev_get_drvdata(dev);
struct qpnp_iadc_result result;
int rc = -1;
- rc = qpnp_iadc_read(attr->index, &result);
+ rc = qpnp_iadc_read(iadc, attr->index, &result);
if (rc)
return 0;
@@ -925,9 +935,9 @@
static struct sensor_device_attribute qpnp_adc_attr =
SENSOR_ATTR(NULL, S_IRUGO, qpnp_iadc_show, NULL, 0);
-static int32_t qpnp_iadc_init_hwmon(struct spmi_device *spmi)
+static int32_t qpnp_iadc_init_hwmon(struct qpnp_iadc_chip *iadc,
+ struct spmi_device *spmi)
{
- struct qpnp_iadc_drv *iadc = qpnp_iadc;
struct device_node *child;
struct device_node *node = spmi->dev.of_node;
int rc = 0, i = 0, channel;
@@ -959,19 +969,11 @@
static int __devinit qpnp_iadc_probe(struct spmi_device *spmi)
{
- struct qpnp_iadc_drv *iadc;
+ struct qpnp_iadc_chip *iadc;
struct qpnp_adc_drv *adc_qpnp;
struct device_node *node = spmi->dev.of_node;
struct device_node *child;
- int rc, count_adc_channel_list = 0;
-
- if (!node)
- return -EINVAL;
-
- if (qpnp_iadc) {
- pr_err("IADC already in use\n");
- return -EBUSY;
- }
+ int rc, count_adc_channel_list = 0, i = 0;
for_each_child_of_node(node, child)
count_adc_channel_list++;
@@ -981,7 +983,7 @@
return -EINVAL;
}
- iadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_iadc_drv) +
+ iadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_iadc_chip) +
(sizeof(struct sensor_device_attribute) *
count_adc_channel_list), GFP_KERNEL);
if (!iadc) {
@@ -1005,6 +1007,14 @@
goto fail;
}
+ iadc->vadc_dev = qpnp_get_vadc(&spmi->dev, "iadc");
+ if (IS_ERR(iadc->vadc_dev)) {
+ rc = PTR_ERR(iadc->vadc_dev);
+ if (rc != -EPROBE_DEFER)
+ pr_err("vadc property missing, rc=%d\n", rc);
+ goto fail;
+ }
+
mutex_init(&iadc->adc->adc_lock);
rc = of_property_read_u32(node, "qcom,rsense",
@@ -1021,50 +1031,56 @@
IRQF_TRIGGER_RISING, "qpnp_iadc_interrupt", iadc);
if (rc) {
dev_err(&spmi->dev, "failed to request adc irq\n");
- goto fail;
+ return rc;
} else
enable_irq_wake(iadc->adc->adc_irq_eoc);
- dev_set_drvdata(&spmi->dev, iadc);
- qpnp_iadc = iadc;
-
- rc = qpnp_iadc_init_hwmon(spmi);
+ rc = qpnp_iadc_init_hwmon(iadc, spmi);
if (rc) {
dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
- goto fail;
+ return rc;
}
iadc->iadc_hwmon = hwmon_device_register(&iadc->adc->spmi->dev);
- rc = qpnp_iadc_version_check();
+ rc = qpnp_iadc_version_check(iadc);
if (rc) {
dev_err(&spmi->dev, "IADC version not supported\n");
goto fail;
}
mutex_init(&iadc->iadc_vadc_lock);
+ INIT_WORK(&iadc->trigger_completion_work, qpnp_iadc_trigger_completion);
INIT_DELAYED_WORK(&iadc->iadc_work, qpnp_iadc_work);
- rc = qpnp_iadc_comp_info();
+ rc = qpnp_iadc_comp_info(iadc);
if (rc) {
dev_err(&spmi->dev, "abstracting IADC comp info failed!\n");
goto fail;
}
- iadc->iadc_initialized = true;
- rc = qpnp_iadc_calibrate_for_trim(true);
+ dev_set_drvdata(&spmi->dev, iadc);
+ list_add(&iadc->list, &qpnp_iadc_device_list);
+ rc = qpnp_iadc_calibrate_for_trim(iadc, true);
if (rc)
dev_err(&spmi->dev, "failed to calibrate for USR trim\n");
+
schedule_delayed_work(&iadc->iadc_work,
round_jiffies_relative(msecs_to_jiffies
(QPNP_IADC_CALIB_SECONDS)));
return 0;
fail:
- qpnp_iadc = NULL;
+ for_each_child_of_node(node, child) {
+ device_remove_file(&spmi->dev,
+ &iadc->sens_attr[i].dev_attr);
+ i++;
+ }
+ hwmon_device_unregister(iadc->iadc_hwmon);
+
return rc;
}
static int __devexit qpnp_iadc_remove(struct spmi_device *spmi)
{
- struct qpnp_iadc_drv *iadc = dev_get_drvdata(&spmi->dev);
+ struct qpnp_iadc_chip *iadc = dev_get_drvdata(&spmi->dev);
struct device_node *node = spmi->dev.of_node;
struct device_node *child;
int i = 0;
@@ -1076,6 +1092,7 @@
&iadc->sens_attr[i].dev_attr);
i++;
}
+ hwmon_device_unregister(iadc->iadc_hwmon);
dev_set_drvdata(&spmi->dev, NULL);
return 0;
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index 53e43d1..2fe69fb 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -101,19 +101,21 @@
#define QPNP_ADC_COMPLETION_TIMEOUT HZ
#define QPNP_VADC_ERR_COUNT 5
-struct qpnp_vadc_drv {
+struct qpnp_vadc_chip {
+ struct device *dev;
struct qpnp_adc_drv *adc;
+ struct list_head list;
struct dentry *dent;
struct device *vadc_hwmon;
bool vadc_init_calib;
- bool vadc_initialized;
int max_channels_available;
bool vadc_iadc_sync_lock;
u8 id;
+ struct work_struct trigger_completion_work;
struct sensor_device_attribute sens_attr[0];
};
-struct qpnp_vadc_drv *qpnp_vadc;
+LIST_HEAD(qpnp_vadc_device_list);
static struct qpnp_vadc_scale_fn vadc_scale_fn[] = {
[SCALE_DEFAULT] = {qpnp_adc_scale_default},
@@ -125,9 +127,9 @@
[SCALE_QRD_BATT_THERM] = {qpnp_adc_scale_qrd_batt_therm},
};
-static int32_t qpnp_vadc_read_reg(int16_t reg, u8 *data)
+static int32_t qpnp_vadc_read_reg(struct qpnp_vadc_chip *vadc, int16_t reg,
+ u8 *data)
{
- struct qpnp_vadc_drv *vadc = qpnp_vadc;
int rc;
rc = spmi_ext_register_readl(vadc->adc->spmi->ctrl, vadc->adc->slave,
@@ -140,9 +142,9 @@
return 0;
}
-static int32_t qpnp_vadc_write_reg(int16_t reg, u8 data)
+static int32_t qpnp_vadc_write_reg(struct qpnp_vadc_chip *vadc, int16_t reg,
+ u8 data)
{
- struct qpnp_vadc_drv *vadc = qpnp_vadc;
int rc;
u8 *buf;
@@ -158,24 +160,24 @@
return 0;
}
-static int32_t qpnp_vadc_warm_rst_configure(void)
+static int32_t qpnp_vadc_warm_rst_configure(struct qpnp_vadc_chip *vadc)
{
int rc = 0;
u8 data = 0;
- rc = qpnp_vadc_write_reg(QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA);
+ rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA);
if (rc < 0) {
pr_err("VADC write access failed\n");
return rc;
}
- rc = qpnp_vadc_read_reg(QPNP_VADC_PERH_RESET_CTL3, &data);
+ rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_PERH_RESET_CTL3, &data);
if (rc < 0) {
pr_err("VADC perh reset ctl3 read failed\n");
return rc;
}
- rc = qpnp_vadc_write_reg(QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA);
+ rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA);
if (rc < 0) {
pr_err("VADC write access failed\n");
return rc;
@@ -183,7 +185,7 @@
data |= QPNP_FOLLOW_WARM_RB;
- rc = qpnp_vadc_write_reg(QPNP_VADC_PERH_RESET_CTL3, data);
+ rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_PERH_RESET_CTL3, data);
if (rc < 0) {
pr_err("VADC perh reset ctl3 write failed\n");
return rc;
@@ -192,21 +194,21 @@
return 0;
}
-static int32_t qpnp_vadc_enable(bool state)
+static int32_t qpnp_vadc_enable(struct qpnp_vadc_chip *vadc, bool state)
{
int rc = 0;
u8 data = 0;
data = QPNP_VADC_ADC_EN;
if (state) {
- rc = qpnp_vadc_write_reg(QPNP_VADC_EN_CTL1,
+ rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_EN_CTL1,
data);
if (rc < 0) {
pr_err("VADC enable failed\n");
return rc;
}
} else {
- rc = qpnp_vadc_write_reg(QPNP_VADC_EN_CTL1,
+ rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_EN_CTL1,
(~data & QPNP_VADC_ADC_EN));
if (rc < 0) {
pr_err("VADC disable failed\n");
@@ -217,42 +219,42 @@
return 0;
}
-static int32_t qpnp_vadc_status_debug(void)
+static int32_t qpnp_vadc_status_debug(struct qpnp_vadc_chip *vadc)
{
int rc = 0;
u8 mode = 0, status1 = 0, chan = 0, dig = 0, en = 0, status2 = 0;
- rc = qpnp_vadc_read_reg(QPNP_VADC_MODE_CTL, &mode);
+ rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_MODE_CTL, &mode);
if (rc < 0) {
pr_err("mode ctl register read failed with %d\n", rc);
return rc;
}
- rc = qpnp_vadc_read_reg(QPNP_VADC_ADC_DIG_PARAM, &dig);
+ rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_ADC_DIG_PARAM, &dig);
if (rc < 0) {
pr_err("digital param read failed with %d\n", rc);
return rc;
}
- rc = qpnp_vadc_read_reg(QPNP_VADC_ADC_CH_SEL_CTL, &chan);
+ rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_ADC_CH_SEL_CTL, &chan);
if (rc < 0) {
pr_err("channel read failed with %d\n", rc);
return rc;
}
- rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
+ rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1);
if (rc < 0) {
pr_err("status1 read failed with %d\n", rc);
return rc;
}
- rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS2, &status2);
+ rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS2, &status2);
if (rc < 0) {
pr_err("status2 read failed with %d\n", rc);
return rc;
}
- rc = qpnp_vadc_read_reg(QPNP_VADC_EN_CTL1, &en);
+ rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_EN_CTL1, &en);
if (rc < 0) {
pr_err("en read failed with %d\n", rc);
return rc;
@@ -261,7 +263,7 @@
pr_err("EOC not set - status1/2:%x/%x, dig:%x, ch:%x, mode:%x, en:%x\n",
status1, status2, dig, chan, mode, en);
- rc = qpnp_vadc_enable(false);
+ rc = qpnp_vadc_enable(vadc, false);
if (rc < 0) {
pr_err("VADC disable failed with %d\n", rc);
return rc;
@@ -269,10 +271,9 @@
return 0;
}
-static int32_t qpnp_vadc_configure(
+static int32_t qpnp_vadc_configure(struct qpnp_vadc_chip *vadc,
struct qpnp_adc_amux_properties *chan_prop)
{
- struct qpnp_vadc_drv *vadc = qpnp_vadc;
u8 decimation = 0, conv_sequence = 0, conv_sequence_trig = 0;
u8 mode_ctrl = 0;
int rc = 0;
@@ -280,7 +281,7 @@
/* Mode selection */
mode_ctrl |= ((chan_prop->mode_sel << QPNP_VADC_OP_MODE_SHIFT) |
(QPNP_VADC_ADC_TRIM_EN | QPNP_VADC_AMUX_TRIM_EN));
- rc = qpnp_vadc_write_reg(QPNP_VADC_MODE_CTL, mode_ctrl);
+ rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_MODE_CTL, mode_ctrl);
if (rc < 0) {
pr_err("Mode configure write error\n");
return rc;
@@ -288,7 +289,7 @@
/* Channel selection */
- rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_CH_SEL_CTL,
+ rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_ADC_CH_SEL_CTL,
chan_prop->amux_channel);
if (rc < 0) {
pr_err("Channel configure error\n");
@@ -298,14 +299,14 @@
/* Digital parameter setup */
decimation = chan_prop->decimation <<
QPNP_VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT;
- rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_DIG_PARAM, decimation);
+ rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_ADC_DIG_PARAM, decimation);
if (rc < 0) {
pr_err("Digital parameter configure write error\n");
return rc;
}
/* HW settling time delay */
- rc = qpnp_vadc_write_reg(QPNP_VADC_HW_SETTLE_DELAY,
+ rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_HW_SETTLE_DELAY,
chan_prop->hw_settle_time);
if (rc < 0) {
pr_err("HW settling time setup error\n");
@@ -315,7 +316,7 @@
if (chan_prop->mode_sel == (ADC_OP_NORMAL_MODE <<
QPNP_VADC_OP_MODE_SHIFT)) {
/* Normal measurement mode */
- rc = qpnp_vadc_write_reg(QPNP_VADC_FAST_AVG_CTL,
+ rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_FAST_AVG_CTL,
chan_prop->fast_avg_setup);
if (rc < 0) {
pr_err("Fast averaging configure error\n");
@@ -327,7 +328,7 @@
conv_sequence = ((ADC_SEQ_HOLD_100US <<
QPNP_VADC_CONV_SEQ_HOLDOFF_SHIFT) |
ADC_CONV_SEQ_TIMEOUT_5MS);
- rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_SEQ_CTL,
+ rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_CONV_SEQ_CTL,
conv_sequence);
if (rc < 0) {
pr_err("Conversion sequence error\n");
@@ -337,7 +338,7 @@
conv_sequence_trig = ((QPNP_VADC_CONV_SEQ_RISING_EDGE <<
QPNP_VADC_CONV_SEQ_EDGE_SHIFT) |
chan_prop->trigger_channel);
- rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_SEQ_TRIG_CTL,
+ rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_CONV_SEQ_TRIG_CTL,
conv_sequence_trig);
if (rc < 0) {
pr_err("Conversion trigger error\n");
@@ -347,13 +348,13 @@
INIT_COMPLETION(vadc->adc->adc_rslt_completion);
- rc = qpnp_vadc_enable(true);
+ rc = qpnp_vadc_enable(vadc, true);
if (rc)
return rc;
if (!vadc->vadc_iadc_sync_lock) {
/* Request conversion */
- rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_REQ,
+ rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_CONV_REQ,
QPNP_VADC_CONV_REQ_SET);
if (rc < 0) {
pr_err("Request conversion failed\n");
@@ -364,18 +365,19 @@
return 0;
}
-static int32_t qpnp_vadc_read_conversion_result(int32_t *data)
+static int32_t qpnp_vadc_read_conversion_result(struct qpnp_vadc_chip *vadc,
+ int32_t *data)
{
uint8_t rslt_lsb, rslt_msb;
int rc = 0, status = 0;
- status = qpnp_vadc_read_reg(QPNP_VADC_DATA0, &rslt_lsb);
+ status = qpnp_vadc_read_reg(vadc, QPNP_VADC_DATA0, &rslt_lsb);
if (status < 0) {
pr_err("qpnp adc result read failed for data0\n");
goto fail;
}
- status = qpnp_vadc_read_reg(QPNP_VADC_DATA1, &rslt_msb);
+ status = qpnp_vadc_read_reg(vadc, QPNP_VADC_DATA1, &rslt_msb);
if (status < 0) {
pr_err("qpnp adc result read failed for data1\n");
goto fail;
@@ -390,14 +392,14 @@
}
fail:
- rc = qpnp_vadc_enable(false);
+ rc = qpnp_vadc_enable(vadc, false);
if (rc)
return rc;
return status;
}
-static int32_t qpnp_vadc_read_status(int mode_sel)
+static int32_t qpnp_vadc_read_status(struct qpnp_vadc_chip *vadc, int mode_sel)
{
u8 status1, status2, status2_conv_seq_state;
u8 status_err = QPNP_VADC_CONV_TIMEOUT_ERR;
@@ -405,13 +407,13 @@
switch (mode_sel) {
case (ADC_OP_CONVERSION_SEQUENCER << QPNP_VADC_OP_MODE_SHIFT):
- rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
+ rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1);
if (rc) {
pr_err("qpnp_vadc read mask interrupt failed\n");
return rc;
}
- rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS2, &status2);
+ rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS2, &status2);
if (rc) {
pr_err("qpnp_vadc read mask interrupt failed\n");
return rc;
@@ -437,32 +439,45 @@
return 0;
}
+static int qpnp_vadc_is_valid(struct qpnp_vadc_chip *vadc)
+{
+ struct qpnp_vadc_chip *vadc_chip = NULL;
+
+ list_for_each_entry(vadc_chip, &qpnp_vadc_device_list, list)
+ if (vadc == vadc_chip)
+ return 0;
+
+ return -EINVAL;
+}
+
static void qpnp_vadc_work(struct work_struct *work)
{
- struct qpnp_vadc_drv *vadc = qpnp_vadc;
+ struct qpnp_vadc_chip *vadc = container_of(work,
+ struct qpnp_vadc_chip, trigger_completion_work);
- if (!vadc || !vadc->vadc_initialized)
+ if (qpnp_vadc_is_valid(vadc) < 0)
return;
complete(&vadc->adc->adc_rslt_completion);
return;
}
-DECLARE_WORK(trigger_completion_work, qpnp_vadc_work);
static irqreturn_t qpnp_vadc_isr(int irq, void *dev_id)
{
- schedule_work(&trigger_completion_work);
+ struct qpnp_vadc_chip *vadc = dev_id;
+
+ schedule_work(&vadc->trigger_completion_work);
return IRQ_HANDLED;
}
-static int32_t qpnp_vadc_version_check(void)
+static int32_t qpnp_vadc_version_check(struct qpnp_vadc_chip *dev)
{
uint8_t revision;
int rc;
- rc = qpnp_vadc_read_reg(QPNP_VADC_REVISION2, &revision);
+ rc = qpnp_vadc_read_reg(dev, QPNP_VADC_REVISION2, &revision);
if (rc < 0) {
pr_err("qpnp adc result read failed with %d\n", rc);
return rc;
@@ -510,13 +525,17 @@
return 0;
}
-int32_t qpnp_vbat_sns_comp_result(int64_t *result)
+int32_t qpnp_vbat_sns_comp_result(struct qpnp_vadc_chip *vadc,
+ int64_t *result)
{
- struct qpnp_vadc_drv *vadc = qpnp_vadc;
struct qpnp_vadc_result die_temp_result;
int rc = 0;
- rc = qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
+ rc = qpnp_vadc_is_valid(vadc);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_vadc_conv_seq_request(vadc, ADC_SEQ_NONE,
DIE_TEMP, &die_temp_result);
if (rc < 0) {
pr_err("Error reading die_temp\n");
@@ -532,9 +551,9 @@
}
EXPORT_SYMBOL(qpnp_vbat_sns_comp_result);
-static void qpnp_vadc_625mv_channel_sel(uint32_t *ref_channel_sel)
+static void qpnp_vadc_625mv_channel_sel(struct qpnp_vadc_chip *vadc,
+ uint32_t *ref_channel_sel)
{
- struct qpnp_vadc_drv *vadc = qpnp_vadc;
uint32_t dt_index = 0;
/* Check if the buffered 625mV channel exists */
@@ -551,9 +570,8 @@
}
}
-static int32_t qpnp_vadc_calib_device(void)
+static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc)
{
- struct qpnp_vadc_drv *vadc = qpnp_vadc;
struct qpnp_adc_amux_properties conv;
int rc, calib_read_1, calib_read_2, count = 0;
u8 status1 = 0;
@@ -565,14 +583,14 @@
conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
- rc = qpnp_vadc_configure(&conv);
+ rc = qpnp_vadc_configure(vadc, &conv);
if (rc) {
pr_err("qpnp_vadc configure failed with %d\n", rc);
goto calib_fail;
}
while (status1 != QPNP_VADC_STATUS1_EOC) {
- rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
+ rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1);
if (rc < 0)
return rc;
status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
@@ -585,19 +603,19 @@
}
}
- rc = qpnp_vadc_read_conversion_result(&calib_read_1);
+ rc = qpnp_vadc_read_conversion_result(vadc, &calib_read_1);
if (rc) {
pr_err("qpnp adc read adc failed with %d\n", rc);
goto calib_fail;
}
- qpnp_vadc_625mv_channel_sel(&ref_channel_sel);
+ qpnp_vadc_625mv_channel_sel(vadc, &ref_channel_sel);
conv.amux_channel = ref_channel_sel;
conv.decimation = DECIMATION_TYPE2;
conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
- rc = qpnp_vadc_configure(&conv);
+ rc = qpnp_vadc_configure(vadc, &conv);
if (rc) {
pr_err("qpnp adc configure failed with %d\n", rc);
goto calib_fail;
@@ -606,7 +624,7 @@
status1 = 0;
count = 0;
while (status1 != QPNP_VADC_STATUS1_EOC) {
- rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
+ rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1);
if (rc < 0)
return rc;
status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
@@ -619,7 +637,7 @@
}
}
- rc = qpnp_vadc_read_conversion_result(&calib_read_2);
+ rc = qpnp_vadc_read_conversion_result(vadc, &calib_read_2);
if (rc) {
pr_err("qpnp adc read adc failed with %d\n", rc);
goto calib_fail;
@@ -643,7 +661,7 @@
conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
- rc = qpnp_vadc_configure(&conv);
+ rc = qpnp_vadc_configure(vadc, &conv);
if (rc) {
pr_err("qpnp adc configure failed with %d\n", rc);
goto calib_fail;
@@ -652,7 +670,7 @@
status1 = 0;
count = 0;
while (status1 != QPNP_VADC_STATUS1_EOC) {
- rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
+ rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1);
if (rc < 0)
return rc;
status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
@@ -665,7 +683,7 @@
}
}
- rc = qpnp_vadc_read_conversion_result(&calib_read_1);
+ rc = qpnp_vadc_read_conversion_result(vadc, &calib_read_1);
if (rc) {
pr_err("qpnp adc read adc failed with %d\n", rc);
goto calib_fail;
@@ -676,7 +694,7 @@
conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
- rc = qpnp_vadc_configure(&conv);
+ rc = qpnp_vadc_configure(vadc, &conv);
if (rc) {
pr_err("qpnp adc configure failed with %d\n", rc);
goto calib_fail;
@@ -685,7 +703,7 @@
status1 = 0;
count = 0;
while (status1 != QPNP_VADC_STATUS1_EOC) {
- rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
+ rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1);
if (rc < 0)
return rc;
status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
@@ -698,7 +716,7 @@
}
}
- rc = qpnp_vadc_read_conversion_result(&calib_read_2);
+ rc = qpnp_vadc_read_conversion_result(vadc, &calib_read_2);
if (rc) {
pr_err("qpnp adc read adc failed with %d\n", rc);
goto calib_fail;
@@ -719,11 +737,15 @@
return rc;
}
-int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_linear_graph *param,
+int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_chip *vadc,
+ struct qpnp_vadc_linear_graph *param,
enum qpnp_adc_calib_type calib_type)
{
+ int rc = 0;
- struct qpnp_vadc_drv *vadc = qpnp_vadc;
+ rc = qpnp_vadc_is_valid(vadc);
+ if (rc < 0)
+ return rc;
switch (calib_type) {
case CALIB_RATIOMETRIC:
@@ -752,36 +774,44 @@
}
EXPORT_SYMBOL(qpnp_get_vadc_gain_and_offset);
-int32_t qpnp_vadc_is_ready(void)
+struct qpnp_vadc_chip *qpnp_get_vadc(struct device *dev, const char *name)
{
- struct qpnp_vadc_drv *vadc = qpnp_vadc;
+ struct qpnp_vadc_chip *vadc;
+ struct device_node *node = NULL;
+ char prop_name[QPNP_MAX_PROP_NAME_LEN];
- if (!vadc || !vadc->vadc_initialized)
- return -EPROBE_DEFER;
- else
- return 0;
+ snprintf(prop_name, QPNP_MAX_PROP_NAME_LEN, "qcom,%s-vadc", name);
+
+ node = of_parse_phandle(dev->of_node, prop_name, 0);
+ if (node == NULL)
+ return ERR_PTR(-ENODEV);
+
+ list_for_each_entry(vadc, &qpnp_vadc_device_list, list)
+ if (vadc->adc->spmi->dev.of_node == node)
+ return vadc;
+ return ERR_PTR(-EPROBE_DEFER);
}
-EXPORT_SYMBOL(qpnp_vadc_is_ready);
+EXPORT_SYMBOL(qpnp_get_vadc);
-int32_t qpnp_vadc_conv_seq_request(enum qpnp_vadc_trigger trigger_channel,
+int32_t qpnp_vadc_conv_seq_request(struct qpnp_vadc_chip *vadc,
+ enum qpnp_vadc_trigger trigger_channel,
enum qpnp_vadc_channels channel,
struct qpnp_vadc_result *result)
{
- struct qpnp_vadc_drv *vadc = qpnp_vadc;
int rc = 0, scale_type, amux_prescaling, dt_index = 0;
uint32_t ref_channel;
- if (!vadc || !vadc->vadc_initialized)
+ if (qpnp_vadc_is_valid(vadc))
return -EPROBE_DEFER;
mutex_lock(&vadc->adc->adc_lock);
if (!vadc->vadc_init_calib) {
- rc = qpnp_vadc_version_check();
+ rc = qpnp_vadc_version_check(vadc);
if (rc)
goto fail_unlock;
- rc = qpnp_vadc_calib_device();
+ rc = qpnp_vadc_calib_device(vadc);
if (rc) {
pr_err("Calibration failed\n");
goto fail_unlock;
@@ -790,7 +820,7 @@
}
if (channel == REF_625MV) {
- qpnp_vadc_625mv_channel_sel(&ref_channel);
+ qpnp_vadc_625mv_channel_sel(vadc, &ref_channel);
channel = ref_channel;
}
@@ -826,7 +856,7 @@
vadc->adc->amux_prop->trigger_channel = trigger_channel;
- rc = qpnp_vadc_configure(vadc->adc->amux_prop);
+ rc = qpnp_vadc_configure(vadc, vadc->adc->amux_prop);
if (rc) {
pr_err("qpnp vadc configure failed with %d\n", rc);
goto fail_unlock;
@@ -836,14 +866,14 @@
QPNP_ADC_COMPLETION_TIMEOUT);
if (!rc) {
u8 status1 = 0;
- rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
+ rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1);
if (rc < 0)
goto fail_unlock;
status1 &= (QPNP_VADC_STATUS1_REQ_STS | QPNP_VADC_STATUS1_EOC);
if (status1 == QPNP_VADC_STATUS1_EOC)
pr_debug("End of conversion status set\n");
else {
- rc = qpnp_vadc_status_debug();
+ rc = qpnp_vadc_status_debug(vadc);
if (rc < 0)
pr_err("VADC disable failed\n");
rc = -EINVAL;
@@ -852,12 +882,13 @@
}
if (trigger_channel < ADC_SEQ_NONE) {
- rc = qpnp_vadc_read_status(vadc->adc->amux_prop->mode_sel);
+ rc = qpnp_vadc_read_status(vadc,
+ vadc->adc->amux_prop->mode_sel);
if (rc)
pr_debug("Conversion sequence timed out - %d\n", rc);
}
- rc = qpnp_vadc_read_conversion_result(&result->adc_code);
+ rc = qpnp_vadc_read_conversion_result(vadc, &result->adc_code);
if (rc) {
pr_err("qpnp vadc read adc code failed with %d\n", rc);
goto fail_unlock;
@@ -882,7 +913,7 @@
goto fail_unlock;
}
- vadc_scale_fn[scale_type].chan(result->adc_code,
+ vadc_scale_fn[scale_type].chan(vadc, result->adc_code,
vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);
fail_unlock:
@@ -892,23 +923,22 @@
}
EXPORT_SYMBOL(qpnp_vadc_conv_seq_request);
-int32_t qpnp_vadc_read(enum qpnp_vadc_channels channel,
+int32_t qpnp_vadc_read(struct qpnp_vadc_chip *vadc,
+ enum qpnp_vadc_channels channel,
struct qpnp_vadc_result *result)
{
- struct qpnp_vadc_drv *vadc = qpnp_vadc;
- enum qpnp_vadc_channels;
struct qpnp_vadc_result die_temp_result;
int rc = 0;
if (channel == VBAT_SNS) {
- rc = qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
+ rc = qpnp_vadc_conv_seq_request(vadc, ADC_SEQ_NONE,
channel, result);
if (rc < 0) {
pr_err("Error reading vbatt\n");
return rc;
}
- rc = qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
+ rc = qpnp_vadc_conv_seq_request(vadc, ADC_SEQ_NONE,
DIE_TEMP, &die_temp_result);
if (rc < 0) {
pr_err("Error reading die_temp\n");
@@ -922,41 +952,37 @@
return 0;
} else
- return qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
+ return qpnp_vadc_conv_seq_request(vadc, ADC_SEQ_NONE,
channel, result);
}
EXPORT_SYMBOL(qpnp_vadc_read);
-static void qpnp_vadc_lock(void)
+static void qpnp_vadc_lock(struct qpnp_vadc_chip *vadc)
{
- struct qpnp_vadc_drv *vadc = qpnp_vadc;
-
mutex_lock(&vadc->adc->adc_lock);
}
-static void qpnp_vadc_unlock(void)
+static void qpnp_vadc_unlock(struct qpnp_vadc_chip *vadc)
{
- struct qpnp_vadc_drv *vadc = qpnp_vadc;
-
mutex_unlock(&vadc->adc->adc_lock);
}
-int32_t qpnp_vadc_iadc_sync_request(enum qpnp_vadc_channels channel)
+int32_t qpnp_vadc_iadc_sync_request(struct qpnp_vadc_chip *vadc,
+ enum qpnp_vadc_channels channel)
{
- struct qpnp_vadc_drv *vadc = qpnp_vadc;
int rc = 0, dt_index = 0;
- if (!vadc || !vadc->vadc_initialized)
+ if (qpnp_vadc_is_valid(vadc))
return -EPROBE_DEFER;
- qpnp_vadc_lock();
+ qpnp_vadc_lock(vadc);
if (!vadc->vadc_init_calib) {
- rc = qpnp_vadc_version_check();
+ rc = qpnp_vadc_version_check(vadc);
if (rc)
goto fail;
- rc = qpnp_vadc_calib_device();
+ rc = qpnp_vadc_calib_device(vadc);
if (rc) {
pr_err("Calibration failed\n");
goto fail;
@@ -986,7 +1012,7 @@
<< QPNP_VADC_OP_MODE_SHIFT);
vadc->vadc_iadc_sync_lock = true;
- rc = qpnp_vadc_configure(vadc->adc->amux_prop);
+ rc = qpnp_vadc_configure(vadc, vadc->adc->amux_prop);
if (rc) {
pr_err("qpnp vadc configure failed with %d\n", rc);
goto fail;
@@ -995,15 +1021,15 @@
return rc;
fail:
vadc->vadc_iadc_sync_lock = false;
- qpnp_vadc_unlock();
+ qpnp_vadc_unlock(vadc);
return rc;
}
EXPORT_SYMBOL(qpnp_vadc_iadc_sync_request);
-int32_t qpnp_vadc_iadc_sync_complete_request(enum qpnp_vadc_channels channel,
+int32_t qpnp_vadc_iadc_sync_complete_request(struct qpnp_vadc_chip *vadc,
+ enum qpnp_vadc_channels channel,
struct qpnp_vadc_result *result)
{
- struct qpnp_vadc_drv *vadc = qpnp_vadc;
int rc = 0, scale_type, amux_prescaling, dt_index = 0;
vadc->adc->amux_prop->amux_channel = channel;
@@ -1012,7 +1038,7 @@
!= channel) && (dt_index < vadc->max_channels_available))
dt_index++;
- rc = qpnp_vadc_read_conversion_result(&result->adc_code);
+ rc = qpnp_vadc_read_conversion_result(vadc, &result->adc_code);
if (rc) {
pr_err("qpnp vadc read adc code failed with %d\n", rc);
goto fail;
@@ -1037,12 +1063,12 @@
goto fail;
}
- vadc_scale_fn[scale_type].chan(result->adc_code,
+ vadc_scale_fn[scale_type].chan(vadc, result->adc_code,
vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);
fail:
vadc->vadc_iadc_sync_lock = false;
- qpnp_vadc_unlock();
+ qpnp_vadc_unlock(vadc);
return rc;
}
EXPORT_SYMBOL(qpnp_vadc_iadc_sync_complete_request);
@@ -1051,10 +1077,11 @@
struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct qpnp_vadc_chip *vadc = dev_get_drvdata(dev);
struct qpnp_vadc_result result;
int rc = -1;
- rc = qpnp_vadc_read(attr->index, &result);
+ rc = qpnp_vadc_read(vadc, attr->index, &result);
if (rc) {
pr_err("VADC read error with %d\n", rc);
@@ -1068,9 +1095,9 @@
static struct sensor_device_attribute qpnp_adc_attr =
SENSOR_ATTR(NULL, S_IRUGO, qpnp_adc_show, NULL, 0);
-static int32_t qpnp_vadc_init_hwmon(struct spmi_device *spmi)
+static int32_t qpnp_vadc_init_hwmon(struct qpnp_vadc_chip *vadc,
+ struct spmi_device *spmi)
{
- struct qpnp_vadc_drv *vadc = qpnp_vadc;
struct device_node *child;
struct device_node *node = spmi->dev.of_node;
int rc = 0, i = 0, channel;
@@ -1102,21 +1129,13 @@
static int __devinit qpnp_vadc_probe(struct spmi_device *spmi)
{
- struct qpnp_vadc_drv *vadc;
+ struct qpnp_vadc_chip *vadc;
struct qpnp_adc_drv *adc_qpnp;
struct device_node *node = spmi->dev.of_node;
struct device_node *child;
- int rc, count_adc_channel_list = 0;
+ int rc, count_adc_channel_list = 0, i = 0;
u8 fab_id = 0;
- if (!node)
- return -EINVAL;
-
- if (qpnp_vadc) {
- pr_err("VADC already in use\n");
- return -EBUSY;
- }
-
for_each_child_of_node(node, child)
count_adc_channel_list++;
@@ -1125,7 +1144,7 @@
return -EINVAL;
}
- vadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_vadc_drv) +
+ vadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_vadc_chip) +
(sizeof(struct sensor_device_attribute) *
count_adc_channel_list), GFP_KERNEL);
if (!vadc) {
@@ -1133,20 +1152,19 @@
return -ENOMEM;
}
+ vadc->dev = &(spmi->dev);
adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
GFP_KERNEL);
if (!adc_qpnp) {
dev_err(&spmi->dev, "Unable to allocate memory\n");
- rc = -ENOMEM;
- goto fail;
+ return -ENOMEM;
}
vadc->adc = adc_qpnp;
-
rc = qpnp_adc_get_devicetree_data(spmi, vadc->adc);
if (rc) {
dev_err(&spmi->dev, "failed to read device tree\n");
- goto fail;
+ return rc;
}
mutex_init(&vadc->adc->adc_lock);
@@ -1156,46 +1174,54 @@
if (rc) {
dev_err(&spmi->dev,
"failed to request adc irq with error %d\n", rc);
- goto fail;
+ return rc;
} else {
enable_irq_wake(vadc->adc->adc_irq_eoc);
}
- qpnp_vadc = vadc;
- dev_set_drvdata(&spmi->dev, vadc);
- rc = qpnp_vadc_init_hwmon(spmi);
+ rc = qpnp_vadc_init_hwmon(vadc, spmi);
if (rc) {
dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
- goto fail;
+ return rc;
}
vadc->vadc_hwmon = hwmon_device_register(&vadc->adc->spmi->dev);
vadc->vadc_init_calib = false;
vadc->max_channels_available = count_adc_channel_list;
- rc = qpnp_vadc_read_reg(QPNP_INT_TEST_VAL, &fab_id);
+ rc = qpnp_vadc_read_reg(vadc, QPNP_INT_TEST_VAL, &fab_id);
if (rc < 0) {
pr_err("qpnp adc comp id failed with %d\n", rc);
- goto fail;
+ goto err_setup;
}
vadc->id = fab_id;
- rc = qpnp_vadc_warm_rst_configure();
+ rc = qpnp_vadc_warm_rst_configure(vadc);
if (rc < 0) {
pr_err("Setting perp reset on warm reset failed %d\n", rc);
- goto fail;
+ goto err_setup;
}
- vadc->vadc_initialized = true;
+ INIT_WORK(&vadc->trigger_completion_work, qpnp_vadc_work);
vadc->vadc_iadc_sync_lock = false;
+ dev_set_drvdata(&spmi->dev, vadc);
+ list_add(&vadc->list, &qpnp_vadc_device_list);
+
return 0;
-fail:
- qpnp_vadc = NULL;
+
+err_setup:
+ for_each_child_of_node(node, child) {
+ device_remove_file(&spmi->dev,
+ &vadc->sens_attr[i].dev_attr);
+ i++;
+ }
+ hwmon_device_unregister(vadc->vadc_hwmon);
+
return rc;
}
static int __devexit qpnp_vadc_remove(struct spmi_device *spmi)
{
- struct qpnp_vadc_drv *vadc = dev_get_drvdata(&spmi->dev);
+ struct qpnp_vadc_chip *vadc = dev_get_drvdata(&spmi->dev);
struct device_node *node = spmi->dev.of_node;
struct device_node *child;
int i = 0;
@@ -1205,7 +1231,8 @@
&vadc->sens_attr[i].dev_attr);
i++;
}
- vadc->vadc_initialized = false;
+ hwmon_device_unregister(vadc->vadc_hwmon);
+ list_del(&vadc->list);
dev_set_drvdata(&spmi->dev, NULL);
return 0;
diff --git a/drivers/input/misc/cm36283.c b/drivers/input/misc/cm36283.c
new file mode 100644
index 0000000..6280013
--- /dev/null
+++ b/drivers/input/misc/cm36283.c
@@ -0,0 +1,1658 @@
+/* drivers/input/misc/cm36283.c - cm36283 optical sensors driver
+ *
+ * Copyright (C) 2012 Capella Microsystems Inc.
+ * Author: Frank Hsieh <pengyueh@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/irq.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/miscdevice.h>
+#include <linux/lightsensor.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+#include <asm/mach-types.h>
+#include <linux/cm36283.h>
+#include <linux/capella_cm3602.h>
+#include <asm/setup.h>
+#include <linux/wakelock.h>
+#include <linux/jiffies.h>
+
+#define D(x...) pr_info(x)
+
+#define I2C_RETRY_COUNT 10
+
+#define NEAR_DELAY_TIME ((100 * HZ) / 1000)
+
+#define CONTROL_INT_ISR_REPORT 0x00
+#define CONTROL_ALS 0x01
+#define CONTROL_PS 0x02
+
+static int record_init_fail = 0;
+static void sensor_irq_do_work(struct work_struct *work);
+static DECLARE_WORK(sensor_irq_work, sensor_irq_do_work);
+
+struct cm36283_info {
+ struct class *cm36283_class;
+ struct device *ls_dev;
+ struct device *ps_dev;
+
+ struct input_dev *ls_input_dev;
+ struct input_dev *ps_input_dev;
+
+ struct early_suspend early_suspend;
+ struct i2c_client *i2c_client;
+ struct workqueue_struct *lp_wq;
+
+ int intr_pin;
+ int als_enable;
+ int ps_enable;
+ int ps_irq_flag;
+
+ uint16_t *adc_table;
+ uint16_t cali_table[10];
+ int irq;
+
+ int ls_calibrate;
+
+ int (*power)(int, uint8_t); /* power to the chip */
+
+ uint32_t als_kadc;
+ uint32_t als_gadc;
+ uint16_t golden_adc;
+
+ struct wake_lock ps_wake_lock;
+ int psensor_opened;
+ int lightsensor_opened;
+ uint8_t slave_addr;
+
+ uint8_t ps_close_thd_set;
+ uint8_t ps_away_thd_set;
+ int current_level;
+ uint16_t current_adc;
+
+ uint16_t ps_conf1_val;
+ uint16_t ps_conf3_val;
+
+ uint16_t ls_cmd;
+ uint8_t record_clear_int_fail;
+};
+struct cm36283_info *lp_info;
+int fLevel=-1;
+static struct mutex als_enable_mutex, als_disable_mutex, als_get_adc_mutex;
+static struct mutex ps_enable_mutex, ps_disable_mutex, ps_get_adc_mutex;
+static struct mutex CM36283_control_mutex;
+static int lightsensor_enable(struct cm36283_info *lpi);
+static int lightsensor_disable(struct cm36283_info *lpi);
+static int initial_cm36283(struct cm36283_info *lpi);
+static void psensor_initial_cmd(struct cm36283_info *lpi);
+
+int32_t als_kadc;
+
+static int control_and_report(struct cm36283_info *lpi, uint8_t mode, uint16_t param);
+
+static int I2C_RxData(uint16_t slaveAddr, uint8_t cmd, uint8_t *rxData, int length)
+{
+ uint8_t loop_i;
+ int val;
+ struct cm36283_info *lpi = lp_info;
+ uint8_t subaddr[1];
+
+ struct i2c_msg msgs[] = {
+ {
+ .addr = slaveAddr,
+ .flags = 0,
+ .len = 1,
+ .buf = subaddr,
+ },
+ {
+ .addr = slaveAddr,
+ .flags = I2C_M_RD,
+ .len = length,
+ .buf = rxData,
+ },
+ };
+ subaddr[0] = cmd;
+
+ for (loop_i = 0; loop_i < I2C_RETRY_COUNT; loop_i++) {
+
+ if (i2c_transfer(lp_info->i2c_client->adapter, msgs, 2) > 0)
+ break;
+
+ val = gpio_get_value(lpi->intr_pin);
+ /*check intr GPIO when i2c error*/
+ if (loop_i == 0 || loop_i == I2C_RETRY_COUNT -1)
+ D("[PS][CM36283 error] %s, i2c err, slaveAddr 0x%x ISR gpio %d = %d, record_init_fail %d \n",
+ __func__, slaveAddr, lpi->intr_pin, val, record_init_fail);
+
+ msleep(10);
+ }
+ if (loop_i >= I2C_RETRY_COUNT) {
+ printk(KERN_ERR "[PS_ERR][CM36283 error] %s retry over %d\n",
+ __func__, I2C_RETRY_COUNT);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int I2C_TxData(uint16_t slaveAddr, uint8_t *txData, int length)
+{
+ uint8_t loop_i;
+ int val;
+ struct cm36283_info *lpi = lp_info;
+ struct i2c_msg msg[] = {
+ {
+ .addr = slaveAddr,
+ .flags = 0,
+ .len = length,
+ .buf = txData,
+ },
+ };
+
+ for (loop_i = 0; loop_i < I2C_RETRY_COUNT; loop_i++) {
+ if (i2c_transfer(lp_info->i2c_client->adapter, msg, 1) > 0)
+ break;
+
+ val = gpio_get_value(lpi->intr_pin);
+ /*check intr GPIO when i2c error*/
+ if (loop_i == 0 || loop_i == I2C_RETRY_COUNT -1)
+ D("[PS][CM36283 error] %s, i2c err, slaveAddr 0x%x, value 0x%x, ISR gpio%d = %d, record_init_fail %d\n",
+ __func__, slaveAddr, txData[0], lpi->intr_pin, val, record_init_fail);
+
+ msleep(10);
+ }
+
+ if (loop_i >= I2C_RETRY_COUNT) {
+ printk(KERN_ERR "[PS_ERR][CM36283 error] %s retry over %d\n",
+ __func__, I2C_RETRY_COUNT);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int _cm36283_I2C_Read_Word(uint16_t slaveAddr, uint8_t cmd, uint16_t *pdata)
+{
+ uint8_t buffer[2];
+ int ret = 0;
+
+ if (pdata == NULL)
+ return -EFAULT;
+
+ ret = I2C_RxData(slaveAddr, cmd, buffer, 2);
+ if (ret < 0) {
+ pr_err(
+ "[PS_ERR][CM3218 error]%s: I2C_RxData fail [0x%x, 0x%x]\n",
+ __func__, slaveAddr, cmd);
+ return ret;
+ }
+
+ *pdata = (buffer[1]<<8)|buffer[0];
+#if 0
+ /* Debug use */
+ printk(KERN_DEBUG "[CM3218] %s: I2C_RxData[0x%x, 0x%x] = 0x%x\n",
+ __func__, slaveAddr, cmd, *pdata);
+#endif
+ return ret;
+}
+
+static int _cm36283_I2C_Write_Word(uint16_t SlaveAddress, uint8_t cmd, uint16_t data)
+{
+ char buffer[3];
+ int ret = 0;
+#if 0
+ /* Debug use */
+ printk(KERN_DEBUG
+ "[CM3218] %s: _cm36283_I2C_Write_Word[0x%x, 0x%x, 0x%x]\n",
+ __func__, SlaveAddress, cmd, data);
+#endif
+ buffer[0] = cmd;
+ buffer[1] = (uint8_t)(data&0xff);
+ buffer[2] = (uint8_t)((data&0xff00)>>8);
+
+ ret = I2C_TxData(SlaveAddress, buffer, 3);
+ if (ret < 0) {
+ pr_err("[PS_ERR][CM3218 error]%s: I2C_TxData fail\n", __func__);
+ return -EIO;
+ }
+
+ return ret;
+}
+
+static int get_ls_adc_value(uint16_t *als_step, bool resume)
+{
+ struct cm36283_info *lpi = lp_info;
+ uint32_t tmpResult;
+ int ret = 0;
+
+ if (als_step == NULL)
+ return -EFAULT;
+
+ /* Read ALS data: */
+ ret = _cm36283_I2C_Read_Word(lpi->slave_addr, ALS_DATA, als_step);
+ if (ret < 0) {
+ pr_err(
+ "[LS][CM3218 error]%s: _cm36283_I2C_Read_Word fail\n",
+ __func__);
+ return -EIO;
+ }
+
+ if (!lpi->ls_calibrate) {
+ tmpResult = (uint32_t)(*als_step) * lpi->als_gadc / lpi->als_kadc;
+ if (tmpResult > 0xFFFF)
+ *als_step = 0xFFFF;
+ else
+ *als_step = tmpResult;
+ }
+
+ D("[LS][CM3218] %s: raw adc = 0x%X, ls_calibrate = %d\n",
+ __func__, *als_step, lpi->ls_calibrate);
+
+ return ret;
+}
+
+static int set_lsensor_range(uint16_t low_thd, uint16_t high_thd)
+{
+ int ret = 0;
+ struct cm36283_info *lpi = lp_info;
+
+ _cm36283_I2C_Write_Word(lpi->slave_addr, ALS_THDH, high_thd);
+ _cm36283_I2C_Write_Word(lpi->slave_addr, ALS_THDL, low_thd);
+
+ return ret;
+}
+
+static int get_ps_adc_value(uint16_t *data)
+{
+ int ret = 0;
+ struct cm36283_info *lpi = lp_info;
+
+ if (data == NULL)
+ return -EFAULT;
+
+ ret = _cm36283_I2C_Read_Word(lpi->slave_addr, PS_DATA, data);
+
+ (*data) &= 0xFF;
+
+ if (ret < 0) {
+ pr_err(
+ "[PS][CM36283 error]%s: _cm36283_I2C_Read_Word fail\n",
+ __func__);
+ return -EIO;
+ } else {
+ pr_err(
+ "[PS][CM36283 OK]%s: _cm36283_I2C_Read_Word OK 0x%x\n",
+ __func__, *data);
+ }
+
+ return ret;
+}
+
+static uint16_t mid_value(uint16_t value[], uint8_t size)
+{
+ int i = 0, j = 0;
+ uint16_t temp = 0;
+
+ if (size < 3)
+ return 0;
+
+ for (i = 0; i < (size - 1); i++)
+ for (j = (i + 1); j < size; j++)
+ if (value[i] > value[j]) {
+ temp = value[i];
+ value[i] = value[j];
+ value[j] = temp;
+ }
+ return value[((size - 1) / 2)];
+}
+
+static int get_stable_ps_adc_value(uint16_t *ps_adc)
+{
+ uint16_t value[3] = {0, 0, 0}, mid_val = 0;
+ int ret = 0;
+ int i = 0;
+ int wait_count = 0;
+ struct cm36283_info *lpi = lp_info;
+
+ for (i = 0; i < 3; i++) {
+ /*wait interrupt GPIO high*/
+ while (gpio_get_value(lpi->intr_pin) == 0) {
+ msleep(10);
+ wait_count++;
+ if (wait_count > 12) {
+ pr_err("[PS_ERR][CM36283 error]%s: interrupt GPIO low,"
+ " get_ps_adc_value\n", __func__);
+ return -EIO;
+ }
+ }
+
+ ret = get_ps_adc_value(&value[i]);
+ if (ret < 0) {
+ pr_err("[PS_ERR][CM36283 error]%s: get_ps_adc_value\n",
+ __func__);
+ return -EIO;
+ }
+
+ if (wait_count < 60/10) {/*wait gpio less than 60ms*/
+ msleep(60 - (10*wait_count));
+ }
+ wait_count = 0;
+ }
+
+ /*D("Sta_ps: Before sort, value[0, 1, 2] = [0x%x, 0x%x, 0x%x]",
+ value[0], value[1], value[2]);*/
+ mid_val = mid_value(value, 3);
+ D("Sta_ps: After sort, value[0, 1, 2] = [0x%x, 0x%x, 0x%x]",
+ value[0], value[1], value[2]);
+ *ps_adc = (mid_val & 0xFF);
+
+ return 0;
+}
+
+static void sensor_irq_do_work(struct work_struct *work)
+{
+ struct cm36283_info *lpi = lp_info;
+ uint16_t intFlag;
+ _cm36283_I2C_Read_Word(lpi->slave_addr, INT_FLAG, &intFlag);
+ control_and_report(lpi, CONTROL_INT_ISR_REPORT, intFlag);
+
+ enable_irq(lpi->irq);
+}
+
+static irqreturn_t cm36283_irq_handler(int irq, void *data)
+{
+ struct cm36283_info *lpi = data;
+
+ disable_irq_nosync(lpi->irq);
+ queue_work(lpi->lp_wq, &sensor_irq_work);
+
+ return IRQ_HANDLED;
+}
+
+static int als_power(int enable)
+{
+ struct cm36283_info *lpi = lp_info;
+
+ if (lpi->power)
+ lpi->power(LS_PWR_ON, 1);
+
+ return 0;
+}
+
+static void ls_initial_cmd(struct cm36283_info *lpi)
+{
+ /*must disable l-sensor interrupt befrore IST create*//*disable ALS func*/
+ lpi->ls_cmd &= CM36283_ALS_INT_MASK;
+ lpi->ls_cmd |= CM36283_ALS_SD;
+ _cm36283_I2C_Write_Word(lpi->slave_addr, ALS_CONF, lpi->ls_cmd);
+}
+
+static void psensor_initial_cmd(struct cm36283_info *lpi)
+{
+ /*must disable p-sensor interrupt befrore IST create*//*disable ALS func*/
+ lpi->ps_conf1_val |= CM36283_PS_SD;
+ lpi->ps_conf1_val &= CM36283_PS_INT_MASK;
+ _cm36283_I2C_Write_Word(lpi->slave_addr, PS_CONF1, lpi->ps_conf1_val);
+ _cm36283_I2C_Write_Word(lpi->slave_addr, PS_CONF3, lpi->ps_conf3_val);
+ _cm36283_I2C_Write_Word(lpi->slave_addr, PS_THD, (lpi->ps_close_thd_set <<8)| lpi->ps_away_thd_set);
+
+ D("[PS][CM36283] %s, finish\n", __func__);
+}
+
+static int psensor_enable(struct cm36283_info *lpi)
+{
+ int ret = -EIO;
+
+ mutex_lock(&ps_enable_mutex);
+ D("[PS][CM36283] %s\n", __func__);
+
+ if ( lpi->ps_enable ) {
+ D("[PS][CM36283] %s: already enabled\n", __func__);
+ ret = 0;
+ } else
+ ret = control_and_report(lpi, CONTROL_PS, 1);
+
+ mutex_unlock(&ps_enable_mutex);
+ return ret;
+}
+
+static int psensor_disable(struct cm36283_info *lpi)
+{
+ int ret = -EIO;
+
+ mutex_lock(&ps_disable_mutex);
+ D("[PS][CM36283] %s\n", __func__);
+
+ if ( lpi->ps_enable == 0 ) {
+ D("[PS][CM36283] %s: already disabled\n", __func__);
+ ret = 0;
+ } else
+ ret = control_and_report(lpi, CONTROL_PS,0);
+
+ mutex_unlock(&ps_disable_mutex);
+ return ret;
+}
+
+static int psensor_open(struct inode *inode, struct file *file)
+{
+ struct cm36283_info *lpi = lp_info;
+
+ D("[PS][CM36283] %s\n", __func__);
+
+ if (lpi->psensor_opened)
+ return -EBUSY;
+
+ lpi->psensor_opened = 1;
+
+ return 0;
+}
+
+static int psensor_release(struct inode *inode, struct file *file)
+{
+ struct cm36283_info *lpi = lp_info;
+
+ D("[PS][CM36283] %s\n", __func__);
+
+ lpi->psensor_opened = 0;
+
+ return psensor_disable(lpi);
+ //return 0;
+}
+
+static long psensor_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int val;
+ struct cm36283_info *lpi = lp_info;
+
+ D("[PS][CM36283] %s cmd %d\n", __func__, _IOC_NR(cmd));
+
+ switch (cmd) {
+ case CAPELLA_CM3602_IOCTL_ENABLE:
+ if (get_user(val, (unsigned long __user *)arg))
+ return -EFAULT;
+ if (val)
+ return psensor_enable(lpi);
+ else
+ return psensor_disable(lpi);
+ break;
+ case CAPELLA_CM3602_IOCTL_GET_ENABLED:
+ return put_user(lpi->ps_enable, (unsigned long __user *)arg);
+ break;
+ default:
+ pr_err("[PS][CM36283 error]%s: invalid cmd %d\n",
+ __func__, _IOC_NR(cmd));
+ return -EINVAL;
+ }
+}
+
+static const struct file_operations psensor_fops = {
+ .owner = THIS_MODULE,
+ .open = psensor_open,
+ .release = psensor_release,
+ .unlocked_ioctl = psensor_ioctl
+};
+
+struct miscdevice psensor_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "proximity",
+ .fops = &psensor_fops
+};
+
+void lightsensor_set_kvalue(struct cm36283_info *lpi)
+{
+ if (!lpi) {
+ pr_err("[LS][CM36283 error]%s: ls_info is empty\n", __func__);
+ return;
+ }
+
+ D("[LS][CM36283] %s: ALS calibrated als_kadc=0x%x\n",
+ __func__, als_kadc);
+
+ if (als_kadc >> 16 == ALS_CALIBRATED)
+ lpi->als_kadc = als_kadc & 0xFFFF;
+ else {
+ lpi->als_kadc = 0;
+ D("[LS][CM36283] %s: no ALS calibrated\n", __func__);
+ }
+
+ if (lpi->als_kadc && lpi->golden_adc > 0) {
+ lpi->als_kadc = (lpi->als_kadc > 0 && lpi->als_kadc < 0x1000) ?
+ lpi->als_kadc : lpi->golden_adc;
+ lpi->als_gadc = lpi->golden_adc;
+ } else {
+ lpi->als_kadc = 1;
+ lpi->als_gadc = 1;
+ }
+ D("[LS][CM36283] %s: als_kadc=0x%x, als_gadc=0x%x\n",
+ __func__, lpi->als_kadc, lpi->als_gadc);
+}
+
+
+static int lightsensor_update_table(struct cm36283_info *lpi)
+{
+ uint32_t tmpData[10];
+ int i;
+ for (i = 0; i < 10; i++) {
+ tmpData[i] = (uint32_t)(*(lpi->adc_table + i))
+ * lpi->als_kadc / lpi->als_gadc ;
+ if( tmpData[i] <= 0xFFFF ){
+ lpi->cali_table[i] = (uint16_t) tmpData[i];
+ } else {
+ lpi->cali_table[i] = 0xFFFF;
+ }
+ D("[LS][CM36283] %s: Calibrated adc_table: data[%d], %x\n",
+ __func__, i, lpi->cali_table[i]);
+ }
+
+ return 0;
+}
+
+
+static int lightsensor_enable(struct cm36283_info *lpi)
+{
+ int ret = -EIO;
+
+ mutex_lock(&als_enable_mutex);
+ D("[LS][CM36283] %s\n", __func__);
+
+ if (lpi->als_enable) {
+ D("[LS][CM36283] %s: already enabled\n", __func__);
+ ret = 0;
+ } else
+ ret = control_and_report(lpi, CONTROL_ALS, 1);
+
+ mutex_unlock(&als_enable_mutex);
+ return ret;
+}
+
+static int lightsensor_disable(struct cm36283_info *lpi)
+{
+ int ret = -EIO;
+ mutex_lock(&als_disable_mutex);
+ D("[LS][CM36283] %s\n", __func__);
+
+ if ( lpi->als_enable == 0 ) {
+ D("[LS][CM36283] %s: already disabled\n", __func__);
+ ret = 0;
+ } else
+ ret = control_and_report(lpi, CONTROL_ALS, 0);
+
+ mutex_unlock(&als_disable_mutex);
+ return ret;
+}
+
+static int lightsensor_open(struct inode *inode, struct file *file)
+{
+ struct cm36283_info *lpi = lp_info;
+ int rc = 0;
+
+ D("[LS][CM36283] %s\n", __func__);
+ if (lpi->lightsensor_opened) {
+ pr_err("[LS][CM36283 error]%s: already opened\n", __func__);
+ rc = -EBUSY;
+ }
+ lpi->lightsensor_opened = 1;
+ return rc;
+}
+
+static int lightsensor_release(struct inode *inode, struct file *file)
+{
+ struct cm36283_info *lpi = lp_info;
+
+ D("[LS][CM36283] %s\n", __func__);
+ lpi->lightsensor_opened = 0;
+ return 0;
+}
+
+static long lightsensor_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int rc, val;
+ struct cm36283_info *lpi = lp_info;
+
+ /*D("[CM36283] %s cmd %d\n", __func__, _IOC_NR(cmd));*/
+
+ switch (cmd) {
+ case LIGHTSENSOR_IOCTL_ENABLE:
+ if (get_user(val, (unsigned long __user *)arg)) {
+ rc = -EFAULT;
+ break;
+ }
+ D("[LS][CM36283] %s LIGHTSENSOR_IOCTL_ENABLE, value = %d\n",
+ __func__, val);
+ rc = val ? lightsensor_enable(lpi) : lightsensor_disable(lpi);
+ break;
+ case LIGHTSENSOR_IOCTL_GET_ENABLED:
+ val = lpi->als_enable;
+ D("[LS][CM36283] %s LIGHTSENSOR_IOCTL_GET_ENABLED, enabled %d\n",
+ __func__, val);
+ rc = put_user(val, (unsigned long __user *)arg);
+ break;
+ default:
+ pr_err("[LS][CM36283 error]%s: invalid cmd %d\n",
+ __func__, _IOC_NR(cmd));
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+static const struct file_operations lightsensor_fops = {
+ .owner = THIS_MODULE,
+ .open = lightsensor_open,
+ .release = lightsensor_release,
+ .unlocked_ioctl = lightsensor_ioctl
+};
+
+static struct miscdevice lightsensor_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "lightsensor",
+ .fops = &lightsensor_fops
+};
+
+
+static ssize_t ps_adc_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+ uint16_t value;
+ int ret;
+ struct cm36283_info *lpi = lp_info;
+ int intr_val;
+
+ intr_val = gpio_get_value(lpi->intr_pin);
+
+ get_ps_adc_value(&value);
+
+ ret = sprintf(buf, "ADC[0x%04X], ENABLE = %d, intr_pin = %d\n", value, lpi->ps_enable, intr_val);
+
+ return ret;
+}
+
+static ssize_t ps_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ps_en;
+ struct cm36283_info *lpi = lp_info;
+
+ ps_en = -1;
+ sscanf(buf, "%d", &ps_en);
+
+ if (ps_en != 0 && ps_en != 1
+ && ps_en != 10 && ps_en != 13 && ps_en != 16)
+ return -EINVAL;
+
+ if (ps_en) {
+ D("[PS][CM36283] %s: ps_en=%d\n",
+ __func__, ps_en);
+ psensor_enable(lpi);
+ } else
+ psensor_disable(lpi);
+
+ D("[PS][CM36283] %s\n", __func__);
+
+ return count;
+}
+
+static DEVICE_ATTR(ps_adc, 0664, ps_adc_show, ps_enable_store);
+
+unsigned PS_cmd_test_value;
+static ssize_t ps_parameters_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ struct cm36283_info *lpi = lp_info;
+
+ ret = sprintf(buf, "PS_close_thd_set = 0x%x, PS_away_thd_set = 0x%x, PS_cmd_cmd:value = 0x%x\n",
+ lpi->ps_close_thd_set, lpi->ps_away_thd_set, PS_cmd_test_value);
+
+ return ret;
+}
+
+static ssize_t ps_parameters_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+
+ struct cm36283_info *lpi = lp_info;
+ char *token[10];
+ int i;
+
+ printk(KERN_INFO "[PS][CM36283] %s\n", buf);
+ for (i = 0; i < 3; i++)
+ token[i] = strsep((char **)&buf, " ");
+
+ lpi->ps_close_thd_set = simple_strtoul(token[0], NULL, 16);
+ lpi->ps_away_thd_set = simple_strtoul(token[1], NULL, 16);
+ PS_cmd_test_value = simple_strtoul(token[2], NULL, 16);
+ printk(KERN_INFO
+ "[PS][CM36283]Set PS_close_thd_set = 0x%x, PS_away_thd_set = 0x%x, PS_cmd_cmd:value = 0x%x\n",
+ lpi->ps_close_thd_set, lpi->ps_away_thd_set, PS_cmd_test_value);
+
+ D("[PS][CM36283] %s\n", __func__);
+
+ return count;
+}
+
+static DEVICE_ATTR(ps_parameters, 0664,
+ ps_parameters_show, ps_parameters_store);
+
+
+static ssize_t ps_conf_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cm36283_info *lpi = lp_info;
+ return sprintf(buf, "PS_CONF1 = 0x%x, PS_CONF3 = 0x%x\n", lpi->ps_conf1_val, lpi->ps_conf3_val);
+}
+static ssize_t ps_conf_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int code1, code2;
+ struct cm36283_info *lpi = lp_info;
+
+ sscanf(buf, "0x%x 0x%x", &code1, &code2);
+
+ D("[PS]%s: store value PS conf1 reg = 0x%x PS conf3 reg = 0x%x\n", __func__, code1, code2);
+
+ lpi->ps_conf1_val = code1;
+ lpi->ps_conf3_val = code2;
+
+ _cm36283_I2C_Write_Word(lpi->slave_addr, PS_CONF3, lpi->ps_conf3_val );
+ _cm36283_I2C_Write_Word(lpi->slave_addr, PS_CONF1, lpi->ps_conf1_val );
+
+ return count;
+}
+static DEVICE_ATTR(ps_conf, 0664, ps_conf_show, ps_conf_store);
+
+static ssize_t ps_thd_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ struct cm36283_info *lpi = lp_info;
+ ret = sprintf(buf, "%s ps_close_thd_set = 0x%x, ps_away_thd_set = 0x%x\n", __func__, lpi->ps_close_thd_set, lpi->ps_away_thd_set);
+ return ret;
+}
+static ssize_t ps_thd_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int code;
+ struct cm36283_info *lpi = lp_info;
+
+ sscanf(buf, "0x%x", &code);
+
+ D("[PS]%s: store value = 0x%x\n", __func__, code);
+
+ lpi->ps_away_thd_set = code &0xFF;
+ lpi->ps_close_thd_set = (code &0xFF00)>>8;
+
+ D("[PS]%s: ps_close_thd_set = 0x%x, ps_away_thd_set = 0x%x\n", __func__, lpi->ps_close_thd_set, lpi->ps_away_thd_set);
+
+ return count;
+}
+static DEVICE_ATTR(ps_thd, 0664, ps_thd_show, ps_thd_store);
+
+static ssize_t ps_hw_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret = 0;
+ struct cm36283_info *lpi = lp_info;
+
+ ret = sprintf(buf, "PS1: reg = 0x%x, PS3: reg = 0x%x, ps_close_thd_set = 0x%x, ps_away_thd_set = 0x%x\n",
+ lpi->ps_conf1_val, lpi->ps_conf3_val, lpi->ps_close_thd_set, lpi->ps_away_thd_set);
+
+ return ret;
+}
+static ssize_t ps_hw_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int code;
+// struct cm36283_info *lpi = lp_info;
+
+ sscanf(buf, "0x%x", &code);
+
+ D("[PS]%s: store value = 0x%x\n", __func__, code);
+
+ return count;
+}
+static DEVICE_ATTR(ps_hw, 0664, ps_hw_show, ps_hw_store);
+
+static ssize_t ls_adc_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ struct cm36283_info *lpi = lp_info;
+
+ D("[LS][CM36283] %s: ADC = 0x%04X, Level = %d \n",
+ __func__, lpi->current_adc, lpi->current_level);
+ ret = sprintf(buf, "ADC[0x%04X] => level %d\n",
+ lpi->current_adc, lpi->current_level);
+
+ return ret;
+}
+
+static DEVICE_ATTR(ls_adc, 0664, ls_adc_show, NULL);
+
+static ssize_t ls_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+ int ret = 0;
+ struct cm36283_info *lpi = lp_info;
+
+ ret = sprintf(buf, "Light sensor Auto Enable = %d\n",
+ lpi->als_enable);
+
+ return ret;
+}
+
+static ssize_t ls_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret = 0;
+ int ls_auto;
+ struct cm36283_info *lpi = lp_info;
+
+ ls_auto = -1;
+ sscanf(buf, "%d", &ls_auto);
+
+ if (ls_auto != 0 && ls_auto != 1 && ls_auto != 147)
+ return -EINVAL;
+
+ if (ls_auto) {
+ lpi->ls_calibrate = (ls_auto == 147) ? 1 : 0;
+ ret = lightsensor_enable(lpi);
+ } else {
+ lpi->ls_calibrate = 0;
+ ret = lightsensor_disable(lpi);
+ }
+
+ D("[LS][CM36283] %s: lpi->als_enable = %d, lpi->ls_calibrate = %d, ls_auto=%d\n",
+ __func__, lpi->als_enable, lpi->ls_calibrate, ls_auto);
+
+ if (ret < 0)
+ pr_err(
+ "[LS][CM36283 error]%s: set auto light sensor fail\n",
+ __func__);
+
+ return count;
+}
+
+static DEVICE_ATTR(ls_auto, 0664,
+ ls_enable_show, ls_enable_store);
+
+static ssize_t ls_kadc_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cm36283_info *lpi = lp_info;
+ int ret;
+
+ ret = sprintf(buf, "kadc = 0x%x",
+ lpi->als_kadc);
+
+ return ret;
+}
+
+static ssize_t ls_kadc_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cm36283_info *lpi = lp_info;
+ int kadc_temp = 0;
+
+ sscanf(buf, "%d", &kadc_temp);
+
+ mutex_lock(&als_get_adc_mutex);
+ if(kadc_temp != 0) {
+ lpi->als_kadc = kadc_temp;
+ if( lpi->als_gadc != 0){
+ if (lightsensor_update_table(lpi) < 0)
+ printk(KERN_ERR "[LS][CM36283 error] %s: update ls table fail\n", __func__);
+ } else {
+ printk(KERN_INFO "[LS]%s: als_gadc =0x%x wait to be set\n",
+ __func__, lpi->als_gadc);
+ }
+ } else {
+ printk(KERN_INFO "[LS]%s: als_kadc can't be set to zero\n",
+ __func__);
+ }
+
+ mutex_unlock(&als_get_adc_mutex);
+ return count;
+}
+
+static DEVICE_ATTR(ls_kadc, 0664, ls_kadc_show, ls_kadc_store);
+
+static ssize_t ls_gadc_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cm36283_info *lpi = lp_info;
+ int ret;
+
+ ret = sprintf(buf, "gadc = 0x%x\n", lpi->als_gadc);
+
+ return ret;
+}
+
+static ssize_t ls_gadc_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cm36283_info *lpi = lp_info;
+ int gadc_temp = 0;
+
+ sscanf(buf, "%d", &gadc_temp);
+
+ mutex_lock(&als_get_adc_mutex);
+ if(gadc_temp != 0) {
+ lpi->als_gadc = gadc_temp;
+ if( lpi->als_kadc != 0){
+ if (lightsensor_update_table(lpi) < 0)
+ printk(KERN_ERR "[LS][CM36283 error] %s: update ls table fail\n", __func__);
+ } else {
+ printk(KERN_INFO "[LS]%s: als_kadc =0x%x wait to be set\n",
+ __func__, lpi->als_kadc);
+ }
+ } else {
+ printk(KERN_INFO "[LS]%s: als_gadc can't be set to zero\n",
+ __func__);
+ }
+ mutex_unlock(&als_get_adc_mutex);
+ return count;
+}
+
+static DEVICE_ATTR(ls_gadc, 0664, ls_gadc_show, ls_gadc_store);
+
+static ssize_t ls_adc_table_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned length = 0;
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ length += sprintf(buf + length,
+ "[CM36283]Get adc_table[%d] = 0x%x ; %d, Get cali_table[%d] = 0x%x ; %d, \n",
+ i, *(lp_info->adc_table + i),
+ *(lp_info->adc_table + i),
+ i, *(lp_info->cali_table + i),
+ *(lp_info->cali_table + i));
+ }
+ return length;
+}
+
+static ssize_t ls_adc_table_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+
+ struct cm36283_info *lpi = lp_info;
+ char *token[10];
+ uint16_t tempdata[10];
+ int i;
+
+ printk(KERN_INFO "[LS][CM36283]%s\n", buf);
+ for (i = 0; i < 10; i++) {
+ token[i] = strsep((char **)&buf, " ");
+ tempdata[i] = simple_strtoul(token[i], NULL, 16);
+ if (tempdata[i] < 1 || tempdata[i] > 0xffff) {
+ printk(KERN_ERR
+ "[LS][CM36283 error] adc_table[%d] = 0x%x Err\n",
+ i, tempdata[i]);
+ return count;
+ }
+ }
+ mutex_lock(&als_get_adc_mutex);
+ for (i = 0; i < 10; i++) {
+ lpi->adc_table[i] = tempdata[i];
+ printk(KERN_INFO
+ "[LS][CM36283]Set lpi->adc_table[%d] = 0x%x\n",
+ i, *(lp_info->adc_table + i));
+ }
+ if (lightsensor_update_table(lpi) < 0)
+ printk(KERN_ERR "[LS][CM36283 error] %s: update ls table fail\n",
+ __func__);
+ mutex_unlock(&als_get_adc_mutex);
+ D("[LS][CM36283] %s\n", __func__);
+
+ return count;
+}
+
+static DEVICE_ATTR(ls_adc_table, 0664,
+ ls_adc_table_show, ls_adc_table_store);
+
+static ssize_t ls_conf_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cm36283_info *lpi = lp_info;
+ return sprintf(buf, "ALS_CONF = %x\n", lpi->ls_cmd);
+}
+static ssize_t ls_conf_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cm36283_info *lpi = lp_info;
+ int value = 0;
+ sscanf(buf, "0x%x", &value);
+
+ lpi->ls_cmd = value;
+ printk(KERN_INFO "[LS]set ALS_CONF = %x\n", lpi->ls_cmd);
+
+ _cm36283_I2C_Write_Word(lpi->slave_addr, ALS_CONF, lpi->ls_cmd);
+ return count;
+}
+static DEVICE_ATTR(ls_conf, 0664, ls_conf_show, ls_conf_store);
+
+static ssize_t ls_fLevel_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "fLevel = %d\n", fLevel);
+}
+static ssize_t ls_fLevel_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cm36283_info *lpi = lp_info;
+ int value=0;
+ sscanf(buf, "%d", &value);
+ (value>=0)?(value=min(value,10)):(value=max(value,-1));
+ fLevel=value;
+ input_report_abs(lpi->ls_input_dev, ABS_MISC, fLevel);
+ input_sync(lpi->ls_input_dev);
+ printk(KERN_INFO "[LS]set fLevel = %d\n", fLevel);
+
+ msleep(1000);
+ fLevel=-1;
+ return count;
+}
+static DEVICE_ATTR(ls_flevel, 0664, ls_fLevel_show, ls_fLevel_store);
+
+static int lightsensor_setup(struct cm36283_info *lpi)
+{
+ int ret;
+
+ lpi->ls_input_dev = input_allocate_device();
+ if (!lpi->ls_input_dev) {
+ pr_err(
+ "[LS][CM36283 error]%s: could not allocate ls input device\n",
+ __func__);
+ return -ENOMEM;
+ }
+ lpi->ls_input_dev->name = "cm36283-ls";
+ set_bit(EV_ABS, lpi->ls_input_dev->evbit);
+ input_set_abs_params(lpi->ls_input_dev, ABS_MISC, 0, 9, 0, 0);
+
+ ret = input_register_device(lpi->ls_input_dev);
+ if (ret < 0) {
+ pr_err("[LS][CM36283 error]%s: can not register ls input device\n",
+ __func__);
+ goto err_free_ls_input_device;
+ }
+
+ ret = misc_register(&lightsensor_misc);
+ if (ret < 0) {
+ pr_err("[LS][CM36283 error]%s: can not register ls misc device\n",
+ __func__);
+ goto err_unregister_ls_input_device;
+ }
+
+ return ret;
+
+err_unregister_ls_input_device:
+ input_unregister_device(lpi->ls_input_dev);
+err_free_ls_input_device:
+ input_free_device(lpi->ls_input_dev);
+ return ret;
+}
+
+static int psensor_setup(struct cm36283_info *lpi)
+{
+ int ret;
+
+ lpi->ps_input_dev = input_allocate_device();
+ if (!lpi->ps_input_dev) {
+ pr_err(
+ "[PS][CM36283 error]%s: could not allocate ps input device\n",
+ __func__);
+ return -ENOMEM;
+ }
+ lpi->ps_input_dev->name = "cm36283-ps";
+ set_bit(EV_ABS, lpi->ps_input_dev->evbit);
+ input_set_abs_params(lpi->ps_input_dev, ABS_DISTANCE, 0, 1, 0, 0);
+
+ ret = input_register_device(lpi->ps_input_dev);
+ if (ret < 0) {
+ pr_err(
+ "[PS][CM36283 error]%s: could not register ps input device\n",
+ __func__);
+ goto err_free_ps_input_device;
+ }
+
+ ret = misc_register(&psensor_misc);
+ if (ret < 0) {
+ pr_err(
+ "[PS][CM36283 error]%s: could not register ps misc device\n",
+ __func__);
+ goto err_unregister_ps_input_device;
+ }
+
+ return ret;
+
+err_unregister_ps_input_device:
+ input_unregister_device(lpi->ps_input_dev);
+err_free_ps_input_device:
+ input_free_device(lpi->ps_input_dev);
+ return ret;
+}
+
+
+static int initial_cm36283(struct cm36283_info *lpi)
+{
+ int val, ret;
+ uint16_t idReg;
+
+ val = gpio_get_value(lpi->intr_pin);
+ D("[PS][CM36283] %s, INTERRUPT GPIO val = %d\n", __func__, val);
+
+ ret = _cm36283_I2C_Read_Word(lpi->slave_addr, ID_REG, &idReg);
+ if ((ret < 0) || (idReg != 0xC082)) {
+ if (record_init_fail == 0)
+ record_init_fail = 1;
+ return -ENOMEM;/*If devices without cm36283 chip and did not probe driver*/
+ }
+
+ return 0;
+}
+
+static int cm36283_setup(struct cm36283_info *lpi)
+{
+ int ret = 0;
+
+ als_power(1);
+ msleep(5);
+ ret = gpio_request(lpi->intr_pin, "gpio_cm36283_intr");
+ if (ret < 0) {
+ pr_err("[PS][CM36283 error]%s: gpio %d request failed (%d)\n",
+ __func__, lpi->intr_pin, ret);
+ return ret;
+ }
+
+ ret = gpio_direction_input(lpi->intr_pin);
+ if (ret < 0) {
+ pr_err(
+ "[PS][CM36283 error]%s: fail to set gpio %d as input (%d)\n",
+ __func__, lpi->intr_pin, ret);
+ goto fail_free_intr_pin;
+ }
+
+
+ ret = initial_cm36283(lpi);
+ if (ret < 0) {
+ pr_err(
+ "[PS_ERR][CM36283 error]%s: fail to initial cm36283 (%d)\n",
+ __func__, ret);
+ goto fail_free_intr_pin;
+ }
+
+ /*Default disable P sensor and L sensor*/
+ ls_initial_cmd(lpi);
+ psensor_initial_cmd(lpi);
+
+ ret = request_any_context_irq(lpi->irq,
+ cm36283_irq_handler,
+ IRQF_TRIGGER_LOW,
+ "cm36283",
+ lpi);
+ if (ret < 0) {
+ pr_err(
+ "[PS][CM36283 error]%s: req_irq(%d) fail for gpio %d (%d)\n",
+ __func__, lpi->irq,
+ lpi->intr_pin, ret);
+ goto fail_free_intr_pin;
+ }
+
+ return ret;
+
+fail_free_intr_pin:
+ gpio_free(lpi->intr_pin);
+ return ret;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void cm36283_early_suspend(struct early_suspend *h)
+{
+ struct cm36283_info *lpi = lp_info;
+
+ D("[LS][CM36283] %s\n", __func__);
+
+ if (lpi->als_enable)
+ lightsensor_disable(lpi);
+
+}
+
+static void cm36283_late_resume(struct early_suspend *h)
+{
+ struct cm36283_info *lpi = lp_info;
+
+ D("[LS][CM36283] %s\n", __func__);
+
+ if (!lpi->als_enable)
+ lightsensor_enable(lpi);
+}
+#endif
+
+static int cm36283_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct cm36283_info *lpi;
+ struct cm36283_platform_data *pdata;
+
+ D("[PS][CM36283] %s\n", __func__);
+
+
+ lpi = kzalloc(sizeof(struct cm36283_info), GFP_KERNEL);
+ if (!lpi)
+ return -ENOMEM;
+
+ /*D("[CM36283] %s: client->irq = %d\n", __func__, client->irq);*/
+
+ lpi->i2c_client = client;
+ pdata = client->dev.platform_data;
+ if (!pdata) {
+ pr_err("[PS][CM36283 error]%s: Assign platform_data error!!\n",
+ __func__);
+ ret = -EBUSY;
+ goto err_platform_data_null;
+ }
+
+ lpi->irq = client->irq;
+
+ i2c_set_clientdata(client, lpi);
+
+ lpi->intr_pin = pdata->intr;
+ lpi->adc_table = pdata->levels;
+ lpi->power = pdata->power;
+
+ lpi->slave_addr = pdata->slave_addr;
+
+ lpi->ps_away_thd_set = pdata->ps_away_thd_set;
+ lpi->ps_close_thd_set = pdata->ps_close_thd_set;
+ lpi->ps_conf1_val = pdata->ps_conf1_val;
+ lpi->ps_conf3_val = pdata->ps_conf3_val;
+
+ lpi->ls_cmd = pdata->ls_cmd;
+
+ lpi->record_clear_int_fail=0;
+
+ D("[PS][CM36283] %s: ls_cmd 0x%x\n",
+ __func__, lpi->ls_cmd);
+
+ if (pdata->ls_cmd == 0) {
+ lpi->ls_cmd = CM36283_ALS_IT_160ms | CM36283_ALS_GAIN_2;
+ }
+
+ lp_info = lpi;
+
+ mutex_init(&CM36283_control_mutex);
+
+ mutex_init(&als_enable_mutex);
+ mutex_init(&als_disable_mutex);
+ mutex_init(&als_get_adc_mutex);
+
+ ret = lightsensor_setup(lpi);
+ if (ret < 0) {
+ pr_err("[LS][CM36283 error]%s: lightsensor_setup error!!\n",
+ __func__);
+ goto err_lightsensor_setup;
+ }
+
+ mutex_init(&ps_enable_mutex);
+ mutex_init(&ps_disable_mutex);
+ mutex_init(&ps_get_adc_mutex);
+
+ ret = psensor_setup(lpi);
+ if (ret < 0) {
+ pr_err("[PS][CM36283 error]%s: psensor_setup error!!\n",
+ __func__);
+ goto err_psensor_setup;
+ }
+
+ //SET LUX STEP FACTOR HERE
+ // if adc raw value one step = 5/100 = 1/20 = 0.05 lux
+ // the following will set the factor 0.05 = 1/20
+ // and lpi->golden_adc = 1;
+ // set als_kadc = (ALS_CALIBRATED <<16) | 20;
+
+ als_kadc = (ALS_CALIBRATED <<16) | 20;
+ lpi->golden_adc = 1;
+
+ //ls calibrate always set to 1
+ lpi->ls_calibrate = 1;
+
+ lightsensor_set_kvalue(lpi);
+ ret = lightsensor_update_table(lpi);
+ if (ret < 0) {
+ pr_err("[LS][CM36283 error]%s: update ls table fail\n",
+ __func__);
+ goto err_lightsensor_update_table;
+ }
+
+ lpi->lp_wq = create_singlethread_workqueue("cm36283_wq");
+ if (!lpi->lp_wq) {
+ pr_err("[PS][CM36283 error]%s: can't create workqueue\n", __func__);
+ ret = -ENOMEM;
+ goto err_create_singlethread_workqueue;
+ }
+ wake_lock_init(&(lpi->ps_wake_lock), WAKE_LOCK_SUSPEND, "proximity");
+
+ ret = cm36283_setup(lpi);
+ if (ret < 0) {
+ pr_err("[PS_ERR][CM36283 error]%s: cm36283_setup error!\n", __func__);
+ goto err_cm36283_setup;
+ }
+ lpi->cm36283_class = class_create(THIS_MODULE, "optical_sensors");
+ if (IS_ERR(lpi->cm36283_class)) {
+ ret = PTR_ERR(lpi->cm36283_class);
+ lpi->cm36283_class = NULL;
+ goto err_create_class;
+ }
+
+ lpi->ls_dev = device_create(lpi->cm36283_class,
+ NULL, 0, "%s", "lightsensor");
+ if (unlikely(IS_ERR(lpi->ls_dev))) {
+ ret = PTR_ERR(lpi->ls_dev);
+ lpi->ls_dev = NULL;
+ goto err_create_ls_device;
+ }
+
+ /* register the attributes */
+ ret = device_create_file(lpi->ls_dev, &dev_attr_ls_adc);
+ if (ret)
+ goto err_create_ls_device_file;
+
+ /* register the attributes */
+ ret = device_create_file(lpi->ls_dev, &dev_attr_ls_auto);
+ if (ret)
+ goto err_create_ls_device_file;
+
+ /* register the attributes */
+ ret = device_create_file(lpi->ls_dev, &dev_attr_ls_kadc);
+ if (ret)
+ goto err_create_ls_device_file;
+
+ ret = device_create_file(lpi->ls_dev, &dev_attr_ls_gadc);
+ if (ret)
+ goto err_create_ls_device_file;
+
+ ret = device_create_file(lpi->ls_dev, &dev_attr_ls_adc_table);
+ if (ret)
+ goto err_create_ls_device_file;
+
+ ret = device_create_file(lpi->ls_dev, &dev_attr_ls_conf);
+ if (ret)
+ goto err_create_ls_device_file;
+
+ ret = device_create_file(lpi->ls_dev, &dev_attr_ls_flevel);
+ if (ret)
+ goto err_create_ls_device_file;
+
+ lpi->ps_dev = device_create(lpi->cm36283_class,
+ NULL, 0, "%s", "proximity");
+ if (unlikely(IS_ERR(lpi->ps_dev))) {
+ ret = PTR_ERR(lpi->ps_dev);
+ lpi->ps_dev = NULL;
+ goto err_create_ls_device_file;
+ }
+
+ /* register the attributes */
+ ret = device_create_file(lpi->ps_dev, &dev_attr_ps_adc);
+ if (ret)
+ goto err_create_ps_device;
+
+ ret = device_create_file(lpi->ps_dev,
+ &dev_attr_ps_parameters);
+ if (ret)
+ goto err_create_ps_device;
+
+ /* register the attributes */
+ ret = device_create_file(lpi->ps_dev, &dev_attr_ps_conf);
+ if (ret)
+ goto err_create_ps_device;
+
+ /* register the attributes */
+ ret = device_create_file(lpi->ps_dev, &dev_attr_ps_thd);
+ if (ret)
+ goto err_create_ps_device;
+
+ ret = device_create_file(lpi->ps_dev, &dev_attr_ps_hw);
+ if (ret)
+ goto err_create_ps_device;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ lpi->early_suspend.level =
+ EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ lpi->early_suspend.suspend = cm36283_early_suspend;
+ lpi->early_suspend.resume = cm36283_late_resume;
+ register_early_suspend(&lpi->early_suspend);
+#endif
+
+ D("[PS][CM36283] %s: Probe success!\n", __func__);
+
+ return ret;
+
+err_create_ps_device:
+ device_unregister(lpi->ps_dev);
+err_create_ls_device_file:
+ device_unregister(lpi->ls_dev);
+err_create_ls_device:
+ class_destroy(lpi->cm36283_class);
+err_create_class:
+err_cm36283_setup:
+ destroy_workqueue(lpi->lp_wq);
+ wake_lock_destroy(&(lpi->ps_wake_lock));
+
+ input_unregister_device(lpi->ls_input_dev);
+ input_free_device(lpi->ls_input_dev);
+ input_unregister_device(lpi->ps_input_dev);
+ input_free_device(lpi->ps_input_dev);
+err_create_singlethread_workqueue:
+err_lightsensor_update_table:
+ misc_deregister(&psensor_misc);
+err_psensor_setup:
+ mutex_destroy(&CM36283_control_mutex);
+ mutex_destroy(&ps_enable_mutex);
+ mutex_destroy(&ps_disable_mutex);
+ mutex_destroy(&ps_get_adc_mutex);
+ misc_deregister(&lightsensor_misc);
+err_lightsensor_setup:
+ mutex_destroy(&als_enable_mutex);
+ mutex_destroy(&als_disable_mutex);
+ mutex_destroy(&als_get_adc_mutex);
+err_platform_data_null:
+ kfree(lpi);
+ return ret;
+}
+
+static int control_and_report( struct cm36283_info *lpi, uint8_t mode, uint16_t param ) {
+ int ret=0;
+ uint16_t adc_value = 0;
+ uint16_t ps_data = 0;
+ int level = 0, i, val;
+
+ mutex_lock(&CM36283_control_mutex);
+
+ if( mode == CONTROL_ALS ){
+ if(param){
+ lpi->ls_cmd &= CM36283_ALS_SD_MASK;
+ } else {
+ lpi->ls_cmd |= CM36283_ALS_SD;
+ }
+ _cm36283_I2C_Write_Word(lpi->slave_addr, ALS_CONF, lpi->ls_cmd);
+ lpi->als_enable=param;
+ } else if( mode == CONTROL_PS ){
+ if(param){
+ lpi->ps_conf1_val &= CM36283_PS_SD_MASK;
+ lpi->ps_conf1_val |= CM36283_PS_INT_IN_AND_OUT;
+ } else {
+ lpi->ps_conf1_val |= CM36283_PS_SD;
+ lpi->ps_conf1_val &= CM36283_PS_INT_MASK;
+ }
+ _cm36283_I2C_Write_Word(lpi->slave_addr, PS_CONF1, lpi->ps_conf1_val);
+ lpi->ps_enable=param;
+ }
+ if((mode == CONTROL_ALS)||(mode == CONTROL_PS)){
+ if( param==1 ){
+ msleep(100);
+ }
+ }
+
+ if(lpi->als_enable){
+ if( mode == CONTROL_ALS ||
+ ( mode == CONTROL_INT_ISR_REPORT &&
+ ((param&INT_FLAG_ALS_IF_L)||(param&INT_FLAG_ALS_IF_H)))){
+
+ lpi->ls_cmd &= CM36283_ALS_INT_MASK;
+ ret = _cm36283_I2C_Write_Word(lpi->slave_addr, ALS_CONF, lpi->ls_cmd);
+
+ get_ls_adc_value(&adc_value, 0);
+
+ if( lpi->ls_calibrate ) {
+ for (i = 0; i < 10; i++) {
+ if (adc_value <= (*(lpi->cali_table + i))) {
+ level = i;
+ if (*(lpi->cali_table + i))
+ break;
+ }
+ if ( i == 9) {/*avoid i = 10, because 'cali_table' of size is 10 */
+ level = i;
+ break;
+ }
+ }
+ } else {
+ for (i = 0; i < 10; i++) {
+ if (adc_value <= (*(lpi->adc_table + i))) {
+ level = i;
+ if (*(lpi->adc_table + i))
+ break;
+ }
+ if ( i == 9) {/*avoid i = 10, because 'cali_table' of size is 10 */
+ level = i;
+ break;
+ }
+ }
+ }
+
+ ret = set_lsensor_range(((i == 0) || (adc_value == 0)) ? 0 :
+ *(lpi->cali_table + (i - 1)) + 1,
+ *(lpi->cali_table + i));
+
+ lpi->ls_cmd |= CM36283_ALS_INT_EN;
+
+ ret = _cm36283_I2C_Write_Word(lpi->slave_addr, ALS_CONF, lpi->ls_cmd);
+
+ if ((i == 0) || (adc_value == 0))
+ D("[LS][CM3628] %s: ADC=0x%03X, Level=%d, l_thd equal 0, h_thd = 0x%x \n",
+ __func__, adc_value, level, *(lpi->cali_table + i));
+ else
+ D("[LS][CM3628] %s: ADC=0x%03X, Level=%d, l_thd = 0x%x, h_thd = 0x%x \n",
+ __func__, adc_value, level, *(lpi->cali_table + (i - 1)) + 1, *(lpi->cali_table + i));
+ lpi->current_level = level;
+ lpi->current_adc = adc_value;
+ input_report_abs(lpi->ls_input_dev, ABS_MISC, level);
+ input_sync(lpi->ls_input_dev);
+ }
+ }
+
+#define PS_CLOSE 1
+#define PS_AWAY (1<<1)
+#define PS_CLOSE_AND_AWAY PS_CLOSE+PS_AWAY
+
+ if(lpi->ps_enable){
+ int ps_status = 0;
+ if( mode == CONTROL_PS )
+ ps_status = PS_CLOSE_AND_AWAY;
+ else if(mode == CONTROL_INT_ISR_REPORT ){
+ if ( param & INT_FLAG_PS_IF_CLOSE )
+ ps_status |= PS_CLOSE;
+ if ( param & INT_FLAG_PS_IF_AWAY )
+ ps_status |= PS_AWAY;
+ }
+
+ if (ps_status!=0){
+ switch(ps_status){
+ case PS_CLOSE_AND_AWAY:
+ get_stable_ps_adc_value(&ps_data);
+ val = (ps_data >= lpi->ps_close_thd_set) ? 0 : 1;
+ break;
+ case PS_AWAY:
+ val = 1;
+ break;
+ case PS_CLOSE:
+ val = 0;
+ break;
+ };
+ input_report_abs(lpi->ps_input_dev, ABS_DISTANCE, val);
+ input_sync(lpi->ps_input_dev);
+ }
+ }
+
+ mutex_unlock(&CM36283_control_mutex);
+ return ret;
+}
+
+
+static const struct i2c_device_id cm36283_i2c_id[] = {
+ {CM36283_I2C_NAME, 0},
+ {}
+};
+
+static struct i2c_driver cm36283_driver = {
+ .id_table = cm36283_i2c_id,
+ .probe = cm36283_probe,
+ .driver = {
+ .name = CM36283_I2C_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init cm36283_init(void)
+{
+ return i2c_add_driver(&cm36283_driver);
+}
+
+static void __exit cm36283_exit(void)
+{
+ i2c_del_driver(&cm36283_driver);
+}
+
+module_init(cm36283_init);
+module_exit(cm36283_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CM36283 Driver");
+MODULE_AUTHOR("Frank Hsieh <pengyueh@gmail.com>");
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index 519b7e4..ded2b6e 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -302,9 +302,6 @@
/**
* Set/get enable function is just needed by sensor HAL.
- * Normally, the open function does all the initialization
- * and power work. And close undo that open does.
- * Just keeping the function simple.
*/
static ssize_t mpu3050_attr_set_enable(struct device *dev,
@@ -316,8 +313,25 @@
if (kstrtoul(buf, 10, &val))
return -EINVAL;
- sensor->enable = (u32)val;
-
+ sensor->enable = (u32)val == 0 ? 0 : 1;
+ if (sensor->enable) {
+ pm_runtime_get_sync(sensor->dev);
+ gpio_set_value(sensor->enable_gpio, 1);
+ if (sensor->use_poll)
+ schedule_delayed_work(&sensor->input_work,
+ msecs_to_jiffies(sensor->poll_interval));
+ else
+ i2c_smbus_write_byte_data(sensor->client,
+ MPU3050_INT_CFG,
+ MPU3050_ACTIVE_LOW |
+ MPU3050_OPEN_DRAIN |
+ MPU3050_RAW_RDY_EN);
+ } else {
+ if (sensor->use_poll)
+ cancel_delayed_work_sync(&sensor->input_work);
+ gpio_set_value(sensor->enable_gpio, 0);
+ pm_runtime_put(sensor->dev);
+ }
return count;
}
@@ -792,14 +806,8 @@
goto err_input_cleanup;
}
- if (sensor->use_poll)
- schedule_delayed_work(&sensor->input_work,
- msecs_to_jiffies(sensor->poll_interval));
- else
- i2c_smbus_write_byte_data(sensor->client, MPU3050_INT_CFG,
- MPU3050_ACTIVE_LOW |
- MPU3050_OPEN_DRAIN |
- MPU3050_RAW_RDY_EN);
+ pm_runtime_enable(&client->dev);
+ pm_runtime_set_autosuspend_delay(&client->dev, MPU3050_AUTO_DELAY);
return 0;
diff --git a/drivers/input/misc/stk3x1x.c b/drivers/input/misc/stk3x1x.c
new file mode 100644
index 0000000..6e6b9ea
--- /dev/null
+++ b/drivers/input/misc/stk3x1x.c
@@ -0,0 +1,2036 @@
+/*
+ * stk3x1x.c - Linux kernel modules for sensortek stk301x, stk321x and stk331x
+ * proximity/ambient light sensor
+ *
+ * Copyright (c) 2013, The Linux Foundation. All Rights Reserved.
+ * Copyright (C) 2012 Lex Hsieh / sensortek <lex_hsieh@sitronix.com.tw> or
+ * <lex_hsieh@sensortek.com.tw>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Linux Foundation chooses to take subject only to the GPLv2 license
+ * terms, and distributes only under these terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/kdev_t.h>
+#include <linux/fs.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/errno.h>
+#include <linux/wakelock.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+#include "linux/stk3x1x.h"
+
+#define DRIVER_VERSION "3.4.4ts"
+
+/* Driver Settings */
+#define CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD
+#ifdef CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD
+#define STK_ALS_CHANGE_THD 20 /* The threshold to trigger ALS interrupt, unit: lux */
+#endif /* #ifdef CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD */
+#define STK_INT_PS_MODE 1 /* 1, 2, or 3 */
+#define STK_POLL_PS
+#define STK_POLL_ALS /* ALS interrupt is valid only when STK_PS_INT_MODE = 1 or 4*/
+
+#define STK_DEBUG_PRINTF
+
+/* Define Register Map */
+#define STK_STATE_REG 0x00
+#define STK_PSCTRL_REG 0x01
+#define STK_ALSCTRL_REG 0x02
+#define STK_LEDCTRL_REG 0x03
+#define STK_INT_REG 0x04
+#define STK_WAIT_REG 0x05
+#define STK_THDH1_PS_REG 0x06
+#define STK_THDH2_PS_REG 0x07
+#define STK_THDL1_PS_REG 0x08
+#define STK_THDL2_PS_REG 0x09
+#define STK_THDH1_ALS_REG 0x0A
+#define STK_THDH2_ALS_REG 0x0B
+#define STK_THDL1_ALS_REG 0x0C
+#define STK_THDL2_ALS_REG 0x0D
+#define STK_FLAG_REG 0x10
+#define STK_DATA1_PS_REG 0x11
+#define STK_DATA2_PS_REG 0x12
+#define STK_DATA1_ALS_REG 0x13
+#define STK_DATA2_ALS_REG 0x14
+#define STK_DATA1_OFFSET_REG 0x15
+#define STK_DATA2_OFFSET_REG 0x16
+#define STK_DATA1_IR_REG 0x17
+#define STK_DATA2_IR_REG 0x18
+#define STK_PDT_ID_REG 0x3E
+#define STK_RSRVD_REG 0x3F
+#define STK_SW_RESET_REG 0x80
+
+
+/* Define state reg */
+#define STK_STATE_EN_IRS_SHIFT 7
+#define STK_STATE_EN_AK_SHIFT 6
+#define STK_STATE_EN_ASO_SHIFT 5
+#define STK_STATE_EN_IRO_SHIFT 4
+#define STK_STATE_EN_WAIT_SHIFT 2
+#define STK_STATE_EN_ALS_SHIFT 1
+#define STK_STATE_EN_PS_SHIFT 0
+
+#define STK_STATE_EN_IRS_MASK 0x80
+#define STK_STATE_EN_AK_MASK 0x40
+#define STK_STATE_EN_ASO_MASK 0x20
+#define STK_STATE_EN_IRO_MASK 0x10
+#define STK_STATE_EN_WAIT_MASK 0x04
+#define STK_STATE_EN_ALS_MASK 0x02
+#define STK_STATE_EN_PS_MASK 0x01
+
+/* Define PS ctrl reg */
+#define STK_PS_PRS_SHIFT 6
+#define STK_PS_GAIN_SHIFT 4
+#define STK_PS_IT_SHIFT 0
+
+#define STK_PS_PRS_MASK 0xC0
+#define STK_PS_GAIN_MASK 0x30
+#define STK_PS_IT_MASK 0x0F
+
+/* Define ALS ctrl reg */
+#define STK_ALS_PRS_SHIFT 6
+#define STK_ALS_GAIN_SHIFT 4
+#define STK_ALS_IT_SHIFT 0
+
+#define STK_ALS_PRS_MASK 0xC0
+#define STK_ALS_GAIN_MASK 0x30
+#define STK_ALS_IT_MASK 0x0F
+
+/* Define LED ctrl reg */
+#define STK_LED_IRDR_SHIFT 6
+#define STK_LED_DT_SHIFT 0
+
+#define STK_LED_IRDR_MASK 0xC0
+#define STK_LED_DT_MASK 0x3F
+
+/* Define interrupt reg */
+#define STK_INT_CTRL_SHIFT 7
+#define STK_INT_OUI_SHIFT 4
+#define STK_INT_ALS_SHIFT 3
+#define STK_INT_PS_SHIFT 0
+
+#define STK_INT_CTRL_MASK 0x80
+#define STK_INT_OUI_MASK 0x10
+#define STK_INT_ALS_MASK 0x08
+#define STK_INT_PS_MASK 0x07
+
+#define STK_INT_ALS 0x08
+
+/* Define flag reg */
+#define STK_FLG_ALSDR_SHIFT 7
+#define STK_FLG_PSDR_SHIFT 6
+#define STK_FLG_ALSINT_SHIFT 5
+#define STK_FLG_PSINT_SHIFT 4
+#define STK_FLG_OUI_SHIFT 2
+#define STK_FLG_IR_RDY_SHIFT 1
+#define STK_FLG_NF_SHIFT 0
+
+#define STK_FLG_ALSDR_MASK 0x80
+#define STK_FLG_PSDR_MASK 0x40
+#define STK_FLG_ALSINT_MASK 0x20
+#define STK_FLG_PSINT_MASK 0x10
+#define STK_FLG_OUI_MASK 0x04
+#define STK_FLG_IR_RDY_MASK 0x02
+#define STK_FLG_NF_MASK 0x01
+
+/* misc define */
+#define MIN_ALS_POLL_DELAY_NS 110000000
+
+#define DEVICE_NAME "stk_ps"
+#define ALS_NAME "lightsensor-level"
+#define PS_NAME "proximity"
+
+struct stk3x1x_data {
+ struct i2c_client *client;
+#if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS))
+ int32_t irq;
+ struct work_struct stk_work;
+ struct workqueue_struct *stk_wq;
+#endif
+ int int_pin;
+ uint8_t wait_reg;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend stk_early_suspend;
+#endif
+ uint16_t ps_thd_h;
+ uint16_t ps_thd_l;
+ struct mutex io_lock;
+ struct input_dev *ps_input_dev;
+ int32_t ps_distance_last;
+ bool ps_enabled;
+ struct wake_lock ps_wakelock;
+ struct work_struct stk_ps_work;
+ struct workqueue_struct *stk_ps_wq;
+#ifdef STK_POLL_PS
+ struct wake_lock ps_nosuspend_wl;
+#endif
+ struct input_dev *als_input_dev;
+ int32_t als_lux_last;
+ uint32_t als_transmittance;
+ bool als_enabled;
+ struct hrtimer als_timer;
+ struct hrtimer ps_timer;
+ ktime_t als_poll_delay;
+ ktime_t ps_poll_delay;
+#ifdef STK_POLL_ALS
+ struct work_struct stk_als_work;
+ struct workqueue_struct *stk_als_wq;
+#endif
+};
+
+#if( !defined(CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD))
+static uint32_t lux_threshold_table[] =
+{
+ 3,
+ 10,
+ 40,
+ 65,
+ 145,
+ 300,
+ 550,
+ 930,
+ 1250,
+ 1700,
+};
+
+#define LUX_THD_TABLE_SIZE (sizeof(lux_threshold_table)/sizeof(uint32_t)+1)
+static uint16_t code_threshold_table[LUX_THD_TABLE_SIZE+1];
+#endif
+
+static int32_t stk3x1x_enable_ps(struct stk3x1x_data *ps_data, uint8_t enable);
+static int32_t stk3x1x_enable_als(struct stk3x1x_data *ps_data, uint8_t enable);
+static int32_t stk3x1x_set_ps_thd_l(struct stk3x1x_data *ps_data, uint16_t thd_l);
+static int32_t stk3x1x_set_ps_thd_h(struct stk3x1x_data *ps_data, uint16_t thd_h);
+static int32_t stk3x1x_set_als_thd_l(struct stk3x1x_data *ps_data, uint16_t thd_l);
+static int32_t stk3x1x_set_als_thd_h(struct stk3x1x_data *ps_data, uint16_t thd_h);
+//static int32_t stk3x1x_set_ps_aoffset(struct stk3x1x_data *ps_data, uint16_t offset);
+
+inline uint32_t stk_alscode2lux(struct stk3x1x_data *ps_data, uint32_t alscode)
+{
+ alscode += ((alscode<<7)+(alscode<<3)+(alscode>>1));
+ alscode<<=3;
+ alscode/=ps_data->als_transmittance;
+ return alscode;
+}
+
+inline uint32_t stk_lux2alscode(struct stk3x1x_data *ps_data, uint32_t lux)
+{
+ lux*=ps_data->als_transmittance;
+ lux/=1100;
+ if (unlikely(lux>=(1<<16)))
+ lux = (1<<16) -1;
+ return lux;
+}
+
+#ifndef CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD
+static void stk_init_code_threshold_table(struct stk3x1x_data *ps_data)
+{
+ uint32_t i,j;
+ uint32_t alscode;
+
+ code_threshold_table[0] = 0;
+#ifdef STK_DEBUG_PRINTF
+ printk(KERN_INFO "alscode[0]=%d\n",0);
+#endif
+ for (i=1,j=0;i<LUX_THD_TABLE_SIZE;i++,j++)
+ {
+ alscode = stk_lux2alscode(ps_data, lux_threshold_table[j]);
+ printk(KERN_INFO "alscode[%d]=%d\n",i,alscode);
+ code_threshold_table[i] = (uint16_t)(alscode);
+ }
+ code_threshold_table[i] = 0xffff;
+ printk(KERN_INFO "alscode[%d]=%d\n",i,alscode);
+}
+
+static uint32_t stk_get_lux_interval_index(uint16_t alscode)
+{
+ uint32_t i;
+ for (i=1;i<=LUX_THD_TABLE_SIZE;i++)
+ {
+ if ((alscode>=code_threshold_table[i-1])&&(alscode<code_threshold_table[i]))
+ {
+ return i;
+ }
+ }
+ return LUX_THD_TABLE_SIZE;
+}
+#else
+inline void stk_als_set_new_thd(struct stk3x1x_data *ps_data, uint16_t alscode)
+{
+ int32_t high_thd,low_thd;
+ high_thd = alscode + stk_lux2alscode(ps_data, STK_ALS_CHANGE_THD);
+ low_thd = alscode - stk_lux2alscode(ps_data, STK_ALS_CHANGE_THD);
+ if (high_thd >= (1<<16))
+ high_thd = (1<<16) -1;
+ if (low_thd <0)
+ low_thd = 0;
+ stk3x1x_set_als_thd_h(ps_data, (uint16_t)high_thd);
+ stk3x1x_set_als_thd_l(ps_data, (uint16_t)low_thd);
+}
+#endif // CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD
+
+
+static int32_t stk3x1x_init_all_reg(struct stk3x1x_data *ps_data, struct stk3x1x_platform_data *plat_data)
+{
+ int32_t ret;
+ uint8_t w_reg;
+
+ w_reg = plat_data->state_reg;
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_STATE_REG, w_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+
+ ps_data->ps_thd_h = plat_data->ps_thd_h;
+ ps_data->ps_thd_l = plat_data->ps_thd_l;
+
+ w_reg = plat_data->psctrl_reg;
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_PSCTRL_REG, w_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ w_reg = plat_data->alsctrl_reg;
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_ALSCTRL_REG, w_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ w_reg = plat_data->ledctrl_reg;
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_LEDCTRL_REG, w_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ ps_data->wait_reg = plat_data->wait_reg;
+
+ if(ps_data->wait_reg < 2)
+ {
+ printk(KERN_WARNING "%s: wait_reg should be larger than 2, force to write 2\n", __func__);
+ ps_data->wait_reg = 2;
+ }
+ else if (ps_data->wait_reg > 0xFF)
+ {
+ printk(KERN_WARNING "%s: wait_reg should be less than 0xFF, force to write 0xFF\n", __func__);
+ ps_data->wait_reg = 0xFF;
+ }
+ w_reg = plat_data->wait_reg;
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_WAIT_REG, w_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ stk3x1x_set_ps_thd_h(ps_data, ps_data->ps_thd_h);
+ stk3x1x_set_ps_thd_l(ps_data, ps_data->ps_thd_l);
+
+ w_reg = 0;
+#ifndef STK_POLL_PS
+ w_reg |= STK_INT_PS_MODE;
+#else
+ w_reg |= 0x01;
+#endif
+
+#if (!defined(STK_POLL_ALS) && (STK_INT_PS_MODE != 0x02) && (STK_INT_PS_MODE != 0x03))
+ w_reg |= STK_INT_ALS;
+#endif
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_INT_REG, w_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ return 0;
+}
+
+static int32_t stk3x1x_check_pid(struct stk3x1x_data *ps_data)
+{
+ int32_t err1, err2;
+
+ err1 = i2c_smbus_read_byte_data(ps_data->client,STK_PDT_ID_REG);
+ if (err1 < 0)
+ {
+ printk(KERN_ERR "%s: read i2c error, err=%d\n", __func__, err1);
+ return err1;
+ }
+
+ err2 = i2c_smbus_read_byte_data(ps_data->client,STK_RSRVD_REG);
+ if (err2 < 0)
+ {
+ printk(KERN_ERR "%s: read i2c error, err=%d\n", __func__, err2);
+ return -1;
+ }
+ printk(KERN_INFO "%s: PID=0x%x, RID=0x%x\n", __func__, err1, err2);
+ if(err2 == 0xC0)
+ printk(KERN_INFO "%s: RID=0xC0!!!!!!!!!!!!!\n", __func__);
+
+ return 0;
+}
+
+
+static int32_t stk3x1x_software_reset(struct stk3x1x_data *ps_data)
+{
+ int32_t r;
+ uint8_t w_reg;
+
+ w_reg = 0x7F;
+ r = i2c_smbus_write_byte_data(ps_data->client,STK_WAIT_REG,w_reg);
+ if (r<0)
+ {
+ printk(KERN_ERR "%s: software reset: write i2c error, ret=%d\n", __func__, r);
+ return r;
+ }
+ r = i2c_smbus_read_byte_data(ps_data->client,STK_WAIT_REG);
+ if (w_reg != r)
+ {
+ printk(KERN_ERR "%s: software reset: read-back value is not the same\n", __func__);
+ return -1;
+ }
+
+ r = i2c_smbus_write_byte_data(ps_data->client,STK_SW_RESET_REG,0);
+ if (r<0)
+ {
+ printk(KERN_ERR "%s: software reset: read error after reset\n", __func__);
+ return r;
+ }
+ msleep(1);
+ return 0;
+}
+
+
+static int32_t stk3x1x_set_als_thd_l(struct stk3x1x_data *ps_data, uint16_t thd_l)
+{
+ uint8_t temp;
+ uint8_t* pSrc = (uint8_t*)&thd_l;
+ temp = *pSrc;
+ *pSrc = *(pSrc+1);
+ *(pSrc+1) = temp;
+ return i2c_smbus_write_word_data(ps_data->client,STK_THDL1_ALS_REG,thd_l);
+}
+static int32_t stk3x1x_set_als_thd_h(struct stk3x1x_data *ps_data, uint16_t thd_h)
+{
+ uint8_t temp;
+ uint8_t* pSrc = (uint8_t*)&thd_h;
+ temp = *pSrc;
+ *pSrc = *(pSrc+1);
+ *(pSrc+1) = temp;
+ return i2c_smbus_write_word_data(ps_data->client,STK_THDH1_ALS_REG,thd_h);
+}
+
+static int32_t stk3x1x_set_ps_thd_l(struct stk3x1x_data *ps_data, uint16_t thd_l)
+{
+ uint8_t temp;
+ uint8_t* pSrc = (uint8_t*)&thd_l;
+
+ temp = *pSrc;
+ *pSrc = *(pSrc+1);
+ *(pSrc+1) = temp;
+ ps_data->ps_thd_l = thd_l;
+ return i2c_smbus_write_word_data(ps_data->client,STK_THDL1_PS_REG,thd_l);
+}
+
+static int32_t stk3x1x_set_ps_thd_h(struct stk3x1x_data *ps_data, uint16_t thd_h)
+{
+ uint8_t temp;
+ uint8_t* pSrc = (uint8_t*)&thd_h;
+
+ temp = *pSrc;
+ *pSrc = *(pSrc+1);
+ *(pSrc+1) = temp;
+ ps_data->ps_thd_h = thd_h;
+ return i2c_smbus_write_word_data(ps_data->client,STK_THDH1_PS_REG,thd_h);
+}
+
+/*
+static int32_t stk3x1x_set_ps_foffset(struct stk3x1x_data *ps_data, uint16_t offset)
+{
+ uint8_t temp;
+ uint8_t* pSrc = (uint8_t*)&offset;
+ temp = *pSrc;
+ *pSrc = *(pSrc+1);
+ *(pSrc+1) = temp;
+ return i2c_smbus_write_word_data(ps_data->client,STK_DATA1_OFFSET_REG,offset);
+}
+
+static int32_t stk3x1x_set_ps_aoffset(struct stk3x1x_data *ps_data, uint16_t offset)
+{
+ uint8_t temp;
+ uint8_t* pSrc = (uint8_t*)&offset;
+ int ret;
+ uint8_t w_state_reg;
+ uint8_t re_en;
+
+ ret = i2c_smbus_read_byte_data(ps_data->client, STK_STATE_REG);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ re_en = (ret & STK_STATE_EN_AK_MASK) ? 1: 0;
+ if(re_en)
+ {
+ w_state_reg = (uint8_t)(ret & (~STK_STATE_EN_AK_MASK));
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_STATE_REG, w_state_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ msleep(1);
+ }
+ temp = *pSrc;
+ *pSrc = *(pSrc+1);
+ *(pSrc+1) = temp;
+ ret = i2c_smbus_write_word_data(ps_data->client,0x0E,offset);
+ if(!re_en)
+ return ret;
+
+ w_state_reg |= STK_STATE_EN_AK_MASK;
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_STATE_REG, w_state_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+*/
+
+static inline uint32_t stk3x1x_get_ps_reading(struct stk3x1x_data *ps_data)
+{
+ int32_t word_data, tmp_word_data;
+
+ tmp_word_data = i2c_smbus_read_word_data(ps_data->client,STK_DATA1_PS_REG);
+ if(tmp_word_data < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, tmp_word_data);
+ return tmp_word_data;
+ }
+ word_data = ((tmp_word_data & 0xFF00) >> 8) | ((tmp_word_data & 0x00FF) << 8) ;
+ return word_data;
+}
+
+static int32_t stk3x1x_set_flag(struct stk3x1x_data *ps_data, uint8_t org_flag_reg, uint8_t clr)
+{
+ uint8_t w_flag;
+ w_flag = org_flag_reg | (STK_FLG_ALSINT_MASK | STK_FLG_PSINT_MASK | STK_FLG_OUI_MASK | STK_FLG_IR_RDY_MASK);
+ w_flag &= (~clr);
+ //printk(KERN_INFO "%s: org_flag_reg=0x%x, w_flag = 0x%x\n", __func__, org_flag_reg, w_flag);
+ return i2c_smbus_write_byte_data(ps_data->client,STK_FLAG_REG, w_flag);
+}
+
+static int32_t stk3x1x_get_flag(struct stk3x1x_data *ps_data)
+{
+ return i2c_smbus_read_byte_data(ps_data->client,STK_FLAG_REG);
+}
+
+static int32_t stk3x1x_enable_ps(struct stk3x1x_data *ps_data, uint8_t enable)
+{
+ int32_t ret;
+ uint8_t w_state_reg;
+ uint8_t curr_ps_enable;
+ curr_ps_enable = ps_data->ps_enabled?1:0;
+ if(curr_ps_enable == enable)
+ return 0;
+
+ ret = i2c_smbus_read_byte_data(ps_data->client, STK_STATE_REG);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error, ret=%d\n", __func__, ret);
+ return ret;
+ }
+ w_state_reg = ret;
+ w_state_reg &= ~(STK_STATE_EN_PS_MASK | STK_STATE_EN_WAIT_MASK | 0x60);
+ if(enable)
+ {
+ w_state_reg |= STK_STATE_EN_PS_MASK;
+ if(!(ps_data->als_enabled))
+ w_state_reg |= STK_STATE_EN_WAIT_MASK;
+ }
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_STATE_REG, w_state_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error, ret=%d\n", __func__, ret);
+ return ret;
+ }
+
+ if(enable)
+ {
+#ifdef STK_POLL_PS
+ hrtimer_start(&ps_data->ps_timer, ps_data->ps_poll_delay, HRTIMER_MODE_REL);
+ ps_data->ps_distance_last = -1;
+#endif
+ ps_data->ps_enabled = true;
+#ifndef STK_POLL_PS
+#ifndef STK_POLL_ALS
+ if(!(ps_data->als_enabled))
+#endif /* #ifndef STK_POLL_ALS */
+ enable_irq(ps_data->irq);
+ msleep(1);
+ ret = stk3x1x_get_flag(ps_data);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: read i2c error, ret=%d\n", __func__, ret);
+ return ret;
+ }
+
+ near_far_state = ret & STK_FLG_NF_MASK;
+ ps_data->ps_distance_last = near_far_state;
+ input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, near_far_state);
+ input_sync(ps_data->ps_input_dev);
+ wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ);
+ reading = stk3x1x_get_ps_reading(ps_data);
+ printk(KERN_INFO "%s: ps input event=%d, ps code = %d\n",__func__, near_far_state, reading);
+#endif /* #ifndef STK_POLL_PS */
+ }
+ else
+ {
+#ifdef STK_POLL_PS
+ hrtimer_cancel(&ps_data->ps_timer);
+#else
+#ifndef STK_POLL_ALS
+ if(!(ps_data->als_enabled))
+#endif
+ disable_irq(ps_data->irq);
+#endif
+ ps_data->ps_enabled = false;
+ }
+ return ret;
+}
+
+static int32_t stk3x1x_enable_als(struct stk3x1x_data *ps_data, uint8_t enable)
+{
+ int32_t ret;
+ uint8_t w_state_reg;
+ uint8_t curr_als_enable = (ps_data->als_enabled)?1:0;
+
+ if(curr_als_enable == enable)
+ return 0;
+
+#ifndef STK_POLL_ALS
+ if (enable)
+ {
+ stk3x1x_set_als_thd_h(ps_data, 0x0000);
+ stk3x1x_set_als_thd_l(ps_data, 0xFFFF);
+ }
+#endif
+ ret = i2c_smbus_read_byte_data(ps_data->client, STK_STATE_REG);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ w_state_reg = (uint8_t)(ret & (~(STK_STATE_EN_ALS_MASK | STK_STATE_EN_WAIT_MASK)));
+ if(enable)
+ w_state_reg |= STK_STATE_EN_ALS_MASK;
+ else if (ps_data->ps_enabled)
+ w_state_reg |= STK_STATE_EN_WAIT_MASK;
+
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_STATE_REG, w_state_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+
+ if (enable)
+ {
+ ps_data->als_enabled = true;
+#ifdef STK_POLL_ALS
+ hrtimer_start(&ps_data->als_timer, ps_data->als_poll_delay, HRTIMER_MODE_REL);
+#else
+#ifndef STK_POLL_PS
+ if(!(ps_data->ps_enabled))
+#endif
+ enable_irq(ps_data->irq);
+#endif
+ }
+ else
+ {
+ ps_data->als_enabled = false;
+#ifdef STK_POLL_ALS
+ hrtimer_cancel(&ps_data->als_timer);
+#else
+#ifndef STK_POLL_PS
+ if(!(ps_data->ps_enabled))
+#endif
+ disable_irq(ps_data->irq);
+#endif
+ }
+ return ret;
+}
+
+static inline int32_t stk3x1x_get_als_reading(struct stk3x1x_data *ps_data)
+{
+ int32_t word_data, tmp_word_data;
+ tmp_word_data = i2c_smbus_read_word_data(ps_data->client, STK_DATA1_ALS_REG);
+ if(tmp_word_data < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, tmp_word_data);
+ return tmp_word_data;
+ }
+ word_data = ((tmp_word_data & 0xFF00) >> 8) | ((tmp_word_data & 0x00FF) << 8) ;
+ return word_data;
+}
+
+static int32_t stk3x1x_get_ir_reading(struct stk3x1x_data *ps_data)
+{
+ int32_t word_data, tmp_word_data;
+ int32_t ret;
+ uint8_t w_reg, retry = 0;
+
+ if(ps_data->ps_enabled)
+ {
+ stk3x1x_enable_ps(ps_data, 0);
+ ps_data->ps_enabled = true;
+ }
+ ret = i2c_smbus_read_byte_data(ps_data->client, STK_STATE_REG);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ w_reg = (uint8_t)(ret & (~STK_STATE_EN_IRS_MASK));
+ w_reg |= STK_STATE_EN_IRS_MASK;
+
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_STATE_REG, w_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ msleep(100);
+
+ do
+ {
+ msleep(50);
+ ret = stk3x1x_get_flag(ps_data);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ retry++;
+ }while(retry < 5 && ((ret&STK_FLG_IR_RDY_MASK) == 0));
+
+ if(retry == 5)
+ {
+ printk(KERN_ERR "%s: ir data is not ready for 300ms\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = stk3x1x_get_flag(ps_data);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+
+ ret = stk3x1x_set_flag(ps_data, ret, STK_FLG_IR_RDY_MASK);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+
+ tmp_word_data = i2c_smbus_read_word_data(ps_data->client, STK_DATA1_IR_REG);
+ if(tmp_word_data < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, tmp_word_data);
+ return tmp_word_data;
+ }
+ word_data = ((tmp_word_data & 0xFF00) >> 8) | ((tmp_word_data & 0x00FF) << 8) ;
+
+ if(ps_data->ps_enabled)
+ stk3x1x_enable_ps(ps_data, 1);
+ return word_data;
+}
+
+
+static ssize_t stk_als_code_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ int32_t reading;
+
+ reading = stk3x1x_get_als_reading(ps_data);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", reading);
+}
+
+
+static ssize_t stk_als_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ int32_t enable, ret;
+
+ mutex_lock(&ps_data->io_lock);
+ enable = (ps_data->als_enabled)?1:0;
+ mutex_unlock(&ps_data->io_lock);
+ ret = i2c_smbus_read_byte_data(ps_data->client,STK_STATE_REG);
+ ret = (ret & STK_STATE_EN_ALS_MASK)?1:0;
+
+ if(enable != ret)
+ printk(KERN_ERR "%s: driver and sensor mismatch! driver_enable=0x%x, sensor_enable=%x\n", __func__, enable, ret);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+}
+
+static ssize_t stk_als_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ uint8_t en;
+ if (sysfs_streq(buf, "1"))
+ en = 1;
+ else if (sysfs_streq(buf, "0"))
+ en = 0;
+ else
+ {
+ printk(KERN_ERR "%s, invalid value %d\n", __func__, *buf);
+ return -EINVAL;
+ }
+ printk(KERN_INFO "%s: Enable ALS : %d\n", __func__, en);
+ mutex_lock(&ps_data->io_lock);
+ stk3x1x_enable_als(ps_data, en);
+ mutex_unlock(&ps_data->io_lock);
+ return size;
+}
+
+static ssize_t stk_als_lux_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ int32_t als_reading;
+ uint32_t als_lux;
+ als_reading = stk3x1x_get_als_reading(ps_data);
+ mutex_lock(&ps_data->io_lock);
+ als_lux = stk_alscode2lux(ps_data, als_reading);
+ mutex_unlock(&ps_data->io_lock);
+ return scnprintf(buf, PAGE_SIZE, "%d lux\n", als_lux);
+}
+
+static ssize_t stk_als_lux_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ unsigned long value = 0;
+ int ret;
+ ret = kstrtoul(buf, 16, &value);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n",
+ __func__, ret);
+ return ret;
+ }
+ mutex_lock(&ps_data->io_lock);
+ ps_data->als_lux_last = value;
+ input_report_abs(ps_data->als_input_dev, ABS_MISC, value);
+ input_sync(ps_data->als_input_dev);
+ mutex_unlock(&ps_data->io_lock);
+ printk(KERN_INFO "%s: als input event %ld lux\n",__func__, value);
+
+ return size;
+}
+
+
+static ssize_t stk_als_transmittance_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ int32_t transmittance;
+ mutex_lock(&ps_data->io_lock);
+ transmittance = ps_data->als_transmittance;
+ mutex_unlock(&ps_data->io_lock);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", transmittance);
+}
+
+
+static ssize_t stk_als_transmittance_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ unsigned long value = 0;
+ int ret;
+ ret = kstrtoul(buf, 10, &value);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n",
+ __func__, ret);
+ return ret;
+ }
+ mutex_lock(&ps_data->io_lock);
+ ps_data->als_transmittance = value;
+ mutex_unlock(&ps_data->io_lock);
+ return size;
+}
+
+static ssize_t stk_als_delay_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ return scnprintf(buf, PAGE_SIZE, "%lld\n", ktime_to_ns(ps_data->als_poll_delay));
+}
+
+
+static ssize_t stk_als_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ uint64_t value = 0;
+ int ret;
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ ret = kstrtoull(buf, 10, &value);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s:kstrtoull failed, ret=0x%x\n",
+ __func__, ret);
+ return ret;
+ }
+#ifdef STK_DEBUG_PRINTF
+ printk(KERN_INFO "%s: set als poll delay=%lld\n", __func__, value);
+#endif
+ if(value < MIN_ALS_POLL_DELAY_NS)
+ {
+ printk(KERN_ERR "%s: delay is too small\n", __func__);
+ value = MIN_ALS_POLL_DELAY_NS;
+ }
+ mutex_lock(&ps_data->io_lock);
+ if(value != ktime_to_ns(ps_data->als_poll_delay))
+ ps_data->als_poll_delay = ns_to_ktime(value);
+ mutex_unlock(&ps_data->io_lock);
+ return size;
+}
+
+static ssize_t stk_als_ir_code_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ int32_t reading;
+ reading = stk3x1x_get_ir_reading(ps_data);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", reading);
+}
+
+static ssize_t stk_ps_code_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ uint32_t reading;
+ reading = stk3x1x_get_ps_reading(ps_data);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", reading);
+}
+
+static ssize_t stk_ps_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int32_t enable, ret;
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+
+ mutex_lock(&ps_data->io_lock);
+ enable = (ps_data->ps_enabled)?1:0;
+ mutex_unlock(&ps_data->io_lock);
+ ret = i2c_smbus_read_byte_data(ps_data->client,STK_STATE_REG);
+ ret = (ret & STK_STATE_EN_PS_MASK)?1:0;
+
+ if(enable != ret)
+ printk(KERN_ERR "%s: driver and sensor mismatch! driver_enable=0x%x, sensor_enable=%x\n", __func__, enable, ret);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+}
+
+static ssize_t stk_ps_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ uint8_t en;
+ if (sysfs_streq(buf, "1"))
+ en = 1;
+ else if (sysfs_streq(buf, "0"))
+ en = 0;
+ else
+ {
+ printk(KERN_ERR "%s, invalid value %d\n", __func__, *buf);
+ return -EINVAL;
+ }
+ printk(KERN_INFO "%s: Enable PS : %d\n", __func__, en);
+ mutex_lock(&ps_data->io_lock);
+ stk3x1x_enable_ps(ps_data, en);
+ mutex_unlock(&ps_data->io_lock);
+ return size;
+}
+
+static ssize_t stk_ps_enable_aso_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int32_t ret;
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+
+ ret = i2c_smbus_read_byte_data(ps_data->client,STK_STATE_REG);
+ ret = (ret & STK_STATE_EN_ASO_MASK)?1:0;
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+}
+
+static ssize_t stk_ps_enable_aso_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ uint8_t en;
+ int32_t ret;
+ uint8_t w_state_reg;
+
+ if (sysfs_streq(buf, "1"))
+ en = 1;
+ else if (sysfs_streq(buf, "0"))
+ en = 0;
+ else
+ {
+ printk(KERN_ERR "%s, invalid value %d\n", __func__, *buf);
+ return -EINVAL;
+ }
+ printk(KERN_INFO "%s: Enable PS ASO : %d\n", __func__, en);
+
+ ret = i2c_smbus_read_byte_data(ps_data->client, STK_STATE_REG);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ w_state_reg = (uint8_t)(ret & (~STK_STATE_EN_ASO_MASK));
+ if(en)
+ w_state_reg |= STK_STATE_EN_ASO_MASK;
+
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_STATE_REG, w_state_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+
+ return size;
+}
+
+
+static ssize_t stk_ps_offset_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ int32_t word_data, tmp_word_data;
+
+ tmp_word_data = i2c_smbus_read_word_data(ps_data->client, STK_DATA1_OFFSET_REG);
+ if(tmp_word_data < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, tmp_word_data);
+ return tmp_word_data;
+ }
+ word_data = ((tmp_word_data & 0xFF00) >> 8) | ((tmp_word_data & 0x00FF) << 8) ;
+ return scnprintf(buf, PAGE_SIZE, "%d\n", word_data);
+}
+
+static ssize_t stk_ps_offset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ unsigned long value = 0;
+ int ret;
+ uint16_t offset;
+
+ ret = kstrtoul(buf, 10, &value);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n",
+ __func__, ret);
+ return ret;
+ }
+ if(value > 65535)
+ {
+ printk(KERN_ERR "%s: invalid value, offset=%ld\n", __func__, value);
+ return -EINVAL;
+ }
+
+ offset = (uint16_t) ((value&0x00FF) << 8) | ((value&0xFF00) >>8);
+ ret = i2c_smbus_write_word_data(ps_data->client,STK_DATA1_OFFSET_REG,offset);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ return size;
+}
+
+
+static ssize_t stk_ps_distance_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ int32_t dist=1, ret;
+
+ mutex_lock(&ps_data->io_lock);
+ ret = stk3x1x_get_flag(ps_data);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s: stk3x1x_get_flag failed, ret=0x%x\n", __func__, ret);
+ return ret;
+ }
+ dist = (ret & STK_FLG_NF_MASK)?1:0;
+
+ ps_data->ps_distance_last = dist;
+ input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, dist);
+ input_sync(ps_data->ps_input_dev);
+ mutex_unlock(&ps_data->io_lock);
+ wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ);
+ printk(KERN_INFO "%s: ps input event %d cm\n",__func__, dist);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", dist);
+}
+
+
+static ssize_t stk_ps_distance_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ unsigned long value = 0;
+ int ret;
+ ret = kstrtoul(buf, 10, &value);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n",
+ __func__, ret);
+ return ret;
+ }
+ mutex_lock(&ps_data->io_lock);
+ ps_data->ps_distance_last = value;
+ input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, value);
+ input_sync(ps_data->ps_input_dev);
+ mutex_unlock(&ps_data->io_lock);
+ wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ);
+ printk(KERN_INFO "%s: ps input event %ld cm\n",__func__, value);
+ return size;
+}
+
+
+static ssize_t stk_ps_code_thd_l_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int32_t ps_thd_l1_reg, ps_thd_l2_reg;
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ mutex_lock(&ps_data->io_lock);
+ ps_thd_l1_reg = i2c_smbus_read_byte_data(ps_data->client,STK_THDL1_PS_REG);
+ if(ps_thd_l1_reg < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, ps_thd_l1_reg);
+ return -EINVAL;
+ }
+ ps_thd_l2_reg = i2c_smbus_read_byte_data(ps_data->client,STK_THDL2_PS_REG);
+ if(ps_thd_l2_reg < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, ps_thd_l2_reg);
+ return -EINVAL;
+ }
+ mutex_unlock(&ps_data->io_lock);
+ ps_thd_l1_reg = ps_thd_l1_reg<<8 | ps_thd_l2_reg;
+ return scnprintf(buf, PAGE_SIZE, "%d\n", ps_thd_l1_reg);
+}
+
+
+static ssize_t stk_ps_code_thd_l_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ unsigned long value = 0;
+ int ret;
+ ret = kstrtoul(buf, 10, &value);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n",
+ __func__, ret);
+ return ret;
+ }
+ mutex_lock(&ps_data->io_lock);
+ stk3x1x_set_ps_thd_l(ps_data, value);
+ mutex_unlock(&ps_data->io_lock);
+ return size;
+}
+
+static ssize_t stk_ps_code_thd_h_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int32_t ps_thd_h1_reg, ps_thd_h2_reg;
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ mutex_lock(&ps_data->io_lock);
+ ps_thd_h1_reg = i2c_smbus_read_byte_data(ps_data->client,STK_THDH1_PS_REG);
+ if(ps_thd_h1_reg < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, ps_thd_h1_reg);
+ return -EINVAL;
+ }
+ ps_thd_h2_reg = i2c_smbus_read_byte_data(ps_data->client,STK_THDH2_PS_REG);
+ if(ps_thd_h2_reg < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, ps_thd_h2_reg);
+ return -EINVAL;
+ }
+ mutex_unlock(&ps_data->io_lock);
+ ps_thd_h1_reg = ps_thd_h1_reg<<8 | ps_thd_h2_reg;
+ return scnprintf(buf, PAGE_SIZE, "%d\n", ps_thd_h1_reg);
+}
+
+
+static ssize_t stk_ps_code_thd_h_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ unsigned long value = 0;
+ int ret;
+ ret = kstrtoul(buf, 10, &value);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n",
+ __func__, ret);
+ return ret;
+ }
+ mutex_lock(&ps_data->io_lock);
+ stk3x1x_set_ps_thd_h(ps_data, value);
+ mutex_unlock(&ps_data->io_lock);
+ return size;
+}
+
+#if 0
+static ssize_t stk_als_lux_thd_l_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int32_t als_thd_l0_reg,als_thd_l1_reg;
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ uint32_t als_lux;
+
+ mutex_lock(&ps_data->io_lock);
+ als_thd_l0_reg = i2c_smbus_read_byte_data(ps_data->client,STK_THDL1_ALS_REG);
+ als_thd_l1_reg = i2c_smbus_read_byte_data(ps_data->client,STK_THDL2_ALS_REG);
+ if(als_thd_l0_reg < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, als_thd_l0_reg);
+ return -EINVAL;
+ }
+ if(als_thd_l1_reg < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, als_thd_l1_reg);
+ return -EINVAL;
+ }
+ als_thd_l0_reg|=(als_thd_l1_reg<<8);
+ als_lux = stk_alscode2lux(ps_data, als_thd_l0_reg);
+ mutex_unlock(&ps_data->io_lock);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", als_lux);
+}
+
+
+static ssize_t stk_als_lux_thd_l_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ unsigned long value = 0;
+ int ret;
+ ret = kstrtoul(buf, 10, &value);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n",
+ __func__, ret);
+ return ret;
+ }
+ mutex_lock(&ps_data->io_lock);
+ value = stk_lux2alscode(ps_data, value);
+ stk3x1x_set_als_thd_l(ps_data, value);
+ mutex_unlock(&ps_data->io_lock);
+ return size;
+}
+
+static ssize_t stk_als_lux_thd_h_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int32_t als_thd_h0_reg,als_thd_h1_reg;
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ uint32_t als_lux;
+
+ mutex_lock(&ps_data->io_lock);
+ als_thd_h0_reg = i2c_smbus_read_byte_data(ps_data->client,STK_THDH1_ALS_REG);
+ als_thd_h1_reg = i2c_smbus_read_byte_data(ps_data->client,STK_THDH2_ALS_REG);
+ if(als_thd_h0_reg < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, als_thd_h0_reg);
+ return -EINVAL;
+ }
+ if(als_thd_h1_reg < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, als_thd_h1_reg);
+ return -EINVAL;
+ }
+ als_thd_h0_reg|=(als_thd_h1_reg<<8);
+ als_lux = stk_alscode2lux(ps_data, als_thd_h0_reg);
+ mutex_unlock(&ps_data->io_lock);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", als_lux);
+}
+
+
+static ssize_t stk_als_lux_thd_h_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ unsigned long value = 0;
+ int ret;
+ ret = strict_strtoul(buf, 10, &value);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret);
+ return ret;
+ }
+ mutex_lock(&ps_data->io_lock);
+ value = stk_lux2alscode(ps_data, value);
+ stk3x1x_set_als_thd_h(ps_data, value);
+ mutex_unlock(&ps_data->io_lock);
+ return size;
+}
+#endif
+
+
+static ssize_t stk_all_reg_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int32_t ps_reg[27];
+ uint8_t cnt;
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ mutex_lock(&ps_data->io_lock);
+ for(cnt=0;cnt<25;cnt++)
+ {
+ ps_reg[cnt] = i2c_smbus_read_byte_data(ps_data->client, (cnt));
+ if(ps_reg[cnt] < 0)
+ {
+ mutex_unlock(&ps_data->io_lock);
+ printk(KERN_ERR "stk_all_reg_show:i2c_smbus_read_byte_data fail, ret=%d", ps_reg[cnt]);
+ return -EINVAL;
+ }
+ else
+ {
+ printk(KERN_INFO "reg[0x%2X]=0x%2X\n", cnt, ps_reg[cnt]);
+ }
+ }
+ ps_reg[cnt] = i2c_smbus_read_byte_data(ps_data->client, STK_PDT_ID_REG);
+ if(ps_reg[cnt] < 0)
+ {
+ mutex_unlock(&ps_data->io_lock);
+ printk( KERN_ERR "all_reg_show:i2c_smbus_read_byte_data fail, ret=%d", ps_reg[cnt]);
+ return -EINVAL;
+ }
+ printk( KERN_INFO "reg[0x%x]=0x%2X\n", STK_PDT_ID_REG, ps_reg[cnt]);
+ cnt++;
+ ps_reg[cnt] = i2c_smbus_read_byte_data(ps_data->client, STK_RSRVD_REG);
+ if(ps_reg[cnt] < 0)
+ {
+ mutex_unlock(&ps_data->io_lock);
+ printk( KERN_ERR "all_reg_show:i2c_smbus_read_byte_data fail, ret=%d", ps_reg[cnt]);
+ return -EINVAL;
+ }
+ printk( KERN_INFO "reg[0x%x]=0x%2X\n", STK_RSRVD_REG, ps_reg[cnt]);
+ mutex_unlock(&ps_data->io_lock);
+
+ return scnprintf(buf, PAGE_SIZE, "%2X %2X %2X %2X %2X,%2X %2X %2X %2X %2X,%2X %2X %2X %2X %2X,%2X %2X %2X %2X %2X,%2X %2X %2X %2X %2X,%2X %2X\n",
+ ps_reg[0], ps_reg[1], ps_reg[2], ps_reg[3], ps_reg[4], ps_reg[5], ps_reg[6], ps_reg[7], ps_reg[8],
+ ps_reg[9], ps_reg[10], ps_reg[11], ps_reg[12], ps_reg[13], ps_reg[14], ps_reg[15], ps_reg[16], ps_reg[17],
+ ps_reg[18], ps_reg[19], ps_reg[20], ps_reg[21], ps_reg[22], ps_reg[23], ps_reg[24], ps_reg[25], ps_reg[26]);
+}
+
+static ssize_t stk_recv_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return 0;
+}
+
+
+static ssize_t stk_recv_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ unsigned long value = 0;
+ int ret;
+ int32_t recv_data;
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+
+ ret = kstrtoul(buf, 16, &value);
+ if (ret < 0) {
+ printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n",
+ __func__, ret);
+ return ret;
+ }
+ recv_data = i2c_smbus_read_byte_data(ps_data->client,value);
+ printk("%s: reg 0x%x=0x%x\n", __func__, (int)value, recv_data);
+ return size;
+}
+
+
+static ssize_t stk_send_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return 0;
+}
+
+
+static ssize_t stk_send_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ int addr, cmd;
+ u8 addr_u8, cmd_u8;
+ int32_t ret, i;
+ char *token[10];
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+
+ for (i = 0; i < 2; i++)
+ token[i] = strsep((char **)&buf, " ");
+ ret = kstrtoul(token[0], 16, (unsigned long *)&(addr));
+ if (ret < 0) {
+
+ printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n",
+ __func__, ret);
+ return ret;
+ }
+ ret = kstrtoul(token[1], 16, (unsigned long *)&(cmd));
+ if (ret < 0) {
+ printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n",
+ __func__, ret);
+ return ret;
+ }
+ printk(KERN_INFO "%s: write reg 0x%x=0x%x\n", __func__, addr, cmd);
+
+ addr_u8 = (u8) addr;
+ cmd_u8 = (u8) cmd;
+ //mutex_lock(&ps_data->io_lock);
+ ret = i2c_smbus_write_byte_data(ps_data->client,addr_u8,cmd_u8);
+ //mutex_unlock(&ps_data->io_lock);
+ if (0 != ret)
+ {
+ printk(KERN_ERR "%s: i2c_smbus_write_byte_data fail\n", __func__);
+ return ret;
+ }
+
+ return size;
+}
+
+
+static struct device_attribute als_enable_attribute = __ATTR(enable,0664,stk_als_enable_show,stk_als_enable_store);
+static struct device_attribute als_lux_attribute = __ATTR(lux,0664,stk_als_lux_show,stk_als_lux_store);
+static struct device_attribute als_code_attribute = __ATTR(code, 0444, stk_als_code_show, NULL);
+static struct device_attribute als_transmittance_attribute = __ATTR(transmittance,0664,stk_als_transmittance_show,stk_als_transmittance_store);
+static struct device_attribute als_poll_delay_attribute = __ATTR(delay,0664,stk_als_delay_show,stk_als_delay_store);
+static struct device_attribute als_ir_code_attribute = __ATTR(ircode,0444,stk_als_ir_code_show,NULL);
+
+
+static struct attribute *stk_als_attrs [] =
+{
+ &als_enable_attribute.attr,
+ &als_lux_attribute.attr,
+ &als_code_attribute.attr,
+ &als_transmittance_attribute.attr,
+ &als_poll_delay_attribute.attr,
+ &als_ir_code_attribute.attr,
+ NULL
+};
+
+static struct attribute_group stk_als_attribute_group = {
+ .name = "driver",
+ .attrs = stk_als_attrs,
+};
+
+
+static struct device_attribute ps_enable_attribute = __ATTR(enable,0664,stk_ps_enable_show,stk_ps_enable_store);
+static struct device_attribute ps_enable_aso_attribute = __ATTR(enableaso,0664,stk_ps_enable_aso_show,stk_ps_enable_aso_store);
+static struct device_attribute ps_distance_attribute = __ATTR(distance,0664,stk_ps_distance_show, stk_ps_distance_store);
+static struct device_attribute ps_offset_attribute = __ATTR(offset,0664,stk_ps_offset_show, stk_ps_offset_store);
+static struct device_attribute ps_code_attribute = __ATTR(code, 0444, stk_ps_code_show, NULL);
+static struct device_attribute ps_code_thd_l_attribute = __ATTR(codethdl,0664,stk_ps_code_thd_l_show,stk_ps_code_thd_l_store);
+static struct device_attribute ps_code_thd_h_attribute = __ATTR(codethdh,0664,stk_ps_code_thd_h_show,stk_ps_code_thd_h_store);
+static struct device_attribute recv_attribute = __ATTR(recv,0664,stk_recv_show,stk_recv_store);
+static struct device_attribute send_attribute = __ATTR(send,0664,stk_send_show, stk_send_store);
+static struct device_attribute all_reg_attribute = __ATTR(allreg, 0444, stk_all_reg_show, NULL);
+
+static struct attribute *stk_ps_attrs [] =
+{
+ &ps_enable_attribute.attr,
+ &ps_enable_aso_attribute.attr,
+ &ps_distance_attribute.attr,
+ &ps_offset_attribute.attr,
+ &ps_code_attribute.attr,
+ &ps_code_thd_l_attribute.attr,
+ &ps_code_thd_h_attribute.attr,
+ &recv_attribute.attr,
+ &send_attribute.attr,
+ &all_reg_attribute.attr,
+ NULL
+};
+
+static struct attribute_group stk_ps_attribute_group = {
+ .name = "driver",
+ .attrs = stk_ps_attrs,
+};
+
+#ifdef STK_POLL_ALS
+static enum hrtimer_restart stk_als_timer_func(struct hrtimer *timer)
+{
+ struct stk3x1x_data *ps_data = container_of(timer, struct stk3x1x_data, als_timer);
+ queue_work(ps_data->stk_als_wq, &ps_data->stk_als_work);
+ hrtimer_forward_now(&ps_data->als_timer, ps_data->als_poll_delay);
+ return HRTIMER_RESTART;
+}
+
+static void stk_als_work_func(struct work_struct *work)
+{
+ struct stk3x1x_data *ps_data = container_of(work, struct stk3x1x_data, stk_als_work);
+ int32_t reading;
+
+ mutex_lock(&ps_data->io_lock);
+ reading = stk3x1x_get_als_reading(ps_data);
+ if(reading < 0)
+ return;
+ ps_data->als_lux_last = stk_alscode2lux(ps_data, reading);
+ input_report_abs(ps_data->als_input_dev, ABS_MISC, ps_data->als_lux_last);
+ input_sync(ps_data->als_input_dev);
+ mutex_unlock(&ps_data->io_lock);
+ //printk(KERN_INFO "%s: als input event %d lux\n",__func__, ps_data->als_lux_last);
+}
+#endif
+
+static enum hrtimer_restart stk_ps_timer_func(struct hrtimer *timer)
+{
+ struct stk3x1x_data *ps_data = container_of(timer, struct stk3x1x_data, ps_timer);
+ queue_work(ps_data->stk_ps_wq, &ps_data->stk_ps_work);
+#ifdef STK_POLL_PS
+ hrtimer_forward_now(&ps_data->ps_timer, ps_data->ps_poll_delay);
+ return HRTIMER_RESTART;
+#else
+ hrtimer_cancel(&ps_data->ps_timer);
+ return HRTIMER_NORESTART;
+#endif
+}
+
+static void stk_ps_work_func(struct work_struct *work)
+{
+ struct stk3x1x_data *ps_data = container_of(work, struct stk3x1x_data, stk_ps_work);
+ uint32_t reading;
+ int32_t near_far_state;
+ uint8_t org_flag_reg;
+ int32_t ret;
+ uint8_t disable_flag = 0;
+ mutex_lock(&ps_data->io_lock);
+
+ org_flag_reg = stk3x1x_get_flag(ps_data);
+ if(org_flag_reg < 0)
+ {
+ printk(KERN_ERR "%s: get_status_reg fail, ret=%d", __func__, org_flag_reg);
+ goto err_i2c_rw;
+ }
+ near_far_state = (org_flag_reg & STK_FLG_NF_MASK)?1:0;
+ reading = stk3x1x_get_ps_reading(ps_data);
+ if(ps_data->ps_distance_last != near_far_state)
+ {
+ ps_data->ps_distance_last = near_far_state;
+ input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, near_far_state);
+ input_sync(ps_data->ps_input_dev);
+ wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ);
+#ifdef STK_DEBUG_PRINTF
+ printk(KERN_INFO "%s: ps input event %d cm, ps code = %d\n",__func__, near_far_state, reading);
+#endif
+ }
+ ret = stk3x1x_set_flag(ps_data, org_flag_reg, disable_flag);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s:stk3x1x_set_flag fail, ret=%d\n", __func__, ret);
+ goto err_i2c_rw;
+ }
+
+ mutex_unlock(&ps_data->io_lock);
+ return;
+
+err_i2c_rw:
+ mutex_unlock(&ps_data->io_lock);
+ msleep(30);
+ return;
+}
+
+
+#if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS))
+static void stk_work_func(struct work_struct *work)
+{
+ uint32_t reading;
+#if ((STK_INT_PS_MODE != 0x03) && (STK_INT_PS_MODE != 0x02))
+ int32_t ret;
+ uint8_t disable_flag = 0;
+ uint8_t org_flag_reg;
+#endif /* #if ((STK_INT_PS_MODE != 0x03) && (STK_INT_PS_MODE != 0x02)) */
+
+#ifndef CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD
+ uint32_t nLuxIndex;
+#endif
+ struct stk3x1x_data *ps_data = container_of(work, struct stk3x1x_data, stk_work);
+ int32_t near_far_state;
+
+ mutex_lock(&ps_data->io_lock);
+
+#if (STK_INT_PS_MODE == 0x03)
+ near_far_state = gpio_get_value(ps_data->int_pin);
+#elif (STK_INT_PS_MODE == 0x02)
+ near_far_state = !(gpio_get_value(ps_data->int_pin));
+#endif
+
+#if ((STK_INT_PS_MODE == 0x03) || (STK_INT_PS_MODE == 0x02))
+ ps_data->ps_distance_last = near_far_state;
+ input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, near_far_state);
+ input_sync(ps_data->ps_input_dev);
+ wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ);
+ reading = stk3x1x_get_ps_reading(ps_data);
+#ifdef STK_DEBUG_PRINTF
+ printk(KERN_INFO "%s: ps input event %d cm, ps code = %d\n",__func__, near_far_state, reading);
+#endif
+#else
+ /* mode 0x01 or 0x04 */
+ org_flag_reg = stk3x1x_get_flag(ps_data);
+ if(org_flag_reg < 0)
+ {
+ printk(KERN_ERR "%s: get_status_reg fail, org_flag_reg=%d", __func__, org_flag_reg);
+ goto err_i2c_rw;
+ }
+
+ if (org_flag_reg & STK_FLG_ALSINT_MASK)
+ {
+ disable_flag |= STK_FLG_ALSINT_MASK;
+ reading = stk3x1x_get_als_reading(ps_data);
+ if(reading < 0)
+ {
+ printk(KERN_ERR "%s: stk3x1x_get_als_reading fail, ret=%d", __func__, reading);
+ goto err_i2c_rw;
+ }
+#ifndef CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD
+ nLuxIndex = stk_get_lux_interval_index(reading);
+ stk3x1x_set_als_thd_h(ps_data, code_threshold_table[nLuxIndex]);
+ stk3x1x_set_als_thd_l(ps_data, code_threshold_table[nLuxIndex-1]);
+#else
+ stk_als_set_new_thd(ps_data, reading);
+#endif //CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD
+ ps_data->als_lux_last = stk_alscode2lux(ps_data, reading);
+ input_report_abs(ps_data->als_input_dev, ABS_MISC, ps_data->als_lux_last);
+ input_sync(ps_data->als_input_dev);
+#ifdef STK_DEBUG_PRINTF
+ printk(KERN_INFO "%s: als input event %d lux\n",__func__, ps_data->als_lux_last);
+#endif
+ }
+ if (org_flag_reg & STK_FLG_PSINT_MASK)
+ {
+ disable_flag |= STK_FLG_PSINT_MASK;
+ near_far_state = (org_flag_reg & STK_FLG_NF_MASK)?1:0;
+
+ ps_data->ps_distance_last = near_far_state;
+ input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, near_far_state);
+ input_sync(ps_data->ps_input_dev);
+ wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ);
+ reading = stk3x1x_get_ps_reading(ps_data);
+#ifdef STK_DEBUG_PRINTF
+ printk(KERN_INFO "%s: ps input event=%d, ps code = %d\n",__func__, near_far_state, reading);
+#endif
+ }
+
+ ret = stk3x1x_set_flag(ps_data, org_flag_reg, disable_flag);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s:reset_int_flag fail, ret=%d\n", __func__, ret);
+ goto err_i2c_rw;
+ }
+#endif
+
+ msleep(1);
+ enable_irq(ps_data->irq);
+ mutex_unlock(&ps_data->io_lock);
+ return;
+
+err_i2c_rw:
+ mutex_unlock(&ps_data->io_lock);
+ msleep(30);
+ enable_irq(ps_data->irq);
+ return;
+}
+#endif
+
+#if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS))
+static irqreturn_t stk_oss_irq_handler(int irq, void *data)
+{
+ struct stk3x1x_data *pData = data;
+ disable_irq_nosync(irq);
+ queue_work(pData->stk_wq,&pData->stk_work);
+ return IRQ_HANDLED;
+}
+#endif /* #if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS)) */
+static int32_t stk3x1x_init_all_setting(struct i2c_client *client, struct stk3x1x_platform_data *plat_data)
+{
+ int32_t ret;
+ struct stk3x1x_data *ps_data = i2c_get_clientdata(client);
+
+ mutex_lock(&ps_data->io_lock);
+ ps_data->als_enabled = false;
+ ps_data->ps_enabled = false;
+ mutex_unlock(&ps_data->io_lock);
+
+ ret = stk3x1x_software_reset(ps_data);
+ if(ret < 0)
+ return ret;
+
+ stk3x1x_check_pid(ps_data);
+ if(ret < 0)
+ return ret;
+
+ ret = stk3x1x_init_all_reg(ps_data, plat_data);
+ if(ret < 0)
+ return ret;
+#ifndef CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD
+ stk_init_code_threshold_table(ps_data);
+#endif
+ return 0;
+}
+
+#if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS))
+static int stk3x1x_setup_irq(struct i2c_client *client)
+{
+ int irq, err = -EIO;
+ struct stk3x1x_data *ps_data = i2c_get_clientdata(client);
+
+ irq = gpio_to_irq(ps_data->int_pin);
+#ifdef STK_DEBUG_PRINTF
+ printk(KERN_INFO "%s: int pin #=%d, irq=%d\n",__func__, ps_data->int_pin, irq);
+#endif
+ if (irq <= 0)
+ {
+ printk(KERN_ERR "irq number is not specified, irq # = %d, int pin=%d\n",irq, ps_data->int_pin);
+ return irq;
+ }
+ ps_data->irq = irq;
+ err = gpio_request(ps_data->int_pin,"stk-int");
+ if(err < 0)
+ {
+ printk(KERN_ERR "%s: gpio_request, err=%d", __func__, err);
+ return err;
+ }
+ err = gpio_direction_input(ps_data->int_pin);
+ if(err < 0)
+ {
+ printk(KERN_ERR "%s: gpio_direction_input, err=%d", __func__, err);
+ return err;
+ }
+#if ((STK_INT_PS_MODE == 0x03) || (STK_INT_PS_MODE == 0x02))
+ err = request_any_context_irq(irq, stk_oss_irq_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, DEVICE_NAME, ps_data);
+#else
+ err = request_any_context_irq(irq, stk_oss_irq_handler, IRQF_TRIGGER_LOW, DEVICE_NAME, ps_data);
+#endif
+ if (err < 0)
+ {
+ printk(KERN_WARNING "%s: request_any_context_irq(%d) failed for (%d)\n", __func__, irq, err);
+ goto err_request_any_context_irq;
+ }
+ disable_irq(irq);
+
+ return 0;
+err_request_any_context_irq:
+ gpio_free(ps_data->int_pin);
+ return err;
+}
+#endif
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void stk3x1x_early_suspend(struct early_suspend *h)
+{
+ struct stk3x1x_data *ps_data = container_of(h, struct stk3x1x_data, stk_early_suspend);
+#ifndef STK_POLL_PS
+ int err;
+#endif
+
+ printk(KERN_INFO "%s", __func__);
+ mutex_lock(&ps_data->io_lock);
+ if(ps_data->als_enabled)
+ {
+ stk3x1x_enable_als(ps_data, 0);
+ ps_data->als_enabled = true;
+ }
+ if(ps_data->ps_enabled)
+ {
+#ifdef STK_POLL_PS
+ wake_lock(&ps_data->ps_nosuspend_wl);
+#else
+ err = enable_irq_wake(ps_data->irq);
+ if (err)
+ printk(KERN_WARNING "%s: set_irq_wake(%d) failed, err=(%d)\n", __func__, ps_data->irq, err);
+#endif
+ }
+ mutex_unlock(&ps_data->io_lock);
+ return;
+}
+
+static void stk3x1x_late_resume(struct early_suspend *h)
+{
+ struct stk3x1x_data *ps_data = container_of(h, struct stk3x1x_data, stk_early_suspend);
+#ifndef STK_POLL_PS
+ int err;
+#endif
+
+ printk(KERN_INFO "%s", __func__);
+ mutex_lock(&ps_data->io_lock);
+ if(ps_data->als_enabled)
+ stk3x1x_enable_als(ps_data, 1);
+
+ if(ps_data->ps_enabled)
+ {
+#ifdef STK_POLL_PS
+ wake_lock(&ps_data->ps_nosuspend_wl);
+#else
+ err = disable_irq_wake(ps_data->irq);
+ if (err)
+ printk(KERN_WARNING "%s: disable_irq_wake(%d) failed, err=(%d)\n", __func__, ps_data->irq, err);
+#endif
+ }
+ mutex_unlock(&ps_data->io_lock);
+ return;
+}
+#endif //#ifdef CONFIG_HAS_EARLYSUSPEND
+
+
+static int stk3x1x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int err = -ENODEV;
+ struct stk3x1x_data *ps_data;
+ struct stk3x1x_platform_data *plat_data;
+ printk(KERN_INFO "%s: driver version = %s\n", __func__, DRIVER_VERSION);
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ {
+ printk(KERN_ERR "%s: No Support for I2C_FUNC_SMBUS_BYTE_DATA\n", __func__);
+ return -ENODEV;
+ }
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
+ {
+ printk(KERN_ERR "%s: No Support for I2C_FUNC_SMBUS_WORD_DATA\n", __func__);
+ return -ENODEV;
+ }
+
+ ps_data = kzalloc(sizeof(struct stk3x1x_data),GFP_KERNEL);
+ if(!ps_data)
+ {
+ printk(KERN_ERR "%s: failed to allocate stk3x1x_data\n", __func__);
+ return -ENOMEM;
+ }
+ ps_data->client = client;
+ i2c_set_clientdata(client,ps_data);
+ mutex_init(&ps_data->io_lock);
+ wake_lock_init(&ps_data->ps_wakelock,WAKE_LOCK_SUSPEND, "stk_input_wakelock");
+
+#ifdef STK_POLL_PS
+ wake_lock_init(&ps_data->ps_nosuspend_wl,WAKE_LOCK_SUSPEND, "stk_nosuspend_wakelock");
+#endif
+ if(client->dev.platform_data != NULL)
+ {
+ plat_data = client->dev.platform_data;
+ ps_data->als_transmittance = plat_data->transmittance;
+ ps_data->int_pin = plat_data->int_pin;
+ if(ps_data->als_transmittance == 0)
+ {
+ printk(KERN_ERR "%s: Please set als_transmittance in platform data\n", __func__);
+ goto err_als_input_allocate;
+ }
+ }
+ else
+ {
+ printk(KERN_ERR "%s: no stk3x1x platform data!\n", __func__);
+ goto err_als_input_allocate;
+ }
+
+ ps_data->als_input_dev = input_allocate_device();
+ if (ps_data->als_input_dev==NULL)
+ {
+ printk(KERN_ERR "%s: could not allocate als device\n", __func__);
+ err = -ENOMEM;
+ goto err_als_input_allocate;
+ }
+ ps_data->ps_input_dev = input_allocate_device();
+ if (ps_data->ps_input_dev==NULL)
+ {
+ printk(KERN_ERR "%s: could not allocate ps device\n", __func__);
+ err = -ENOMEM;
+ goto err_ps_input_allocate;
+ }
+ ps_data->als_input_dev->name = ALS_NAME;
+ ps_data->ps_input_dev->name = PS_NAME;
+ set_bit(EV_ABS, ps_data->als_input_dev->evbit);
+ set_bit(EV_ABS, ps_data->ps_input_dev->evbit);
+ input_set_abs_params(ps_data->als_input_dev, ABS_MISC, 0, stk_alscode2lux(ps_data, (1<<16)-1), 0, 0);
+ input_set_abs_params(ps_data->ps_input_dev, ABS_DISTANCE, 0,1, 0, 0);
+ err = input_register_device(ps_data->als_input_dev);
+ if (err<0)
+ {
+ printk(KERN_ERR "%s: can not register als input device\n", __func__);
+ goto err_als_input_register;
+ }
+ err = input_register_device(ps_data->ps_input_dev);
+ if (err<0)
+ {
+ printk(KERN_ERR "%s: can not register ps input device\n", __func__);
+ goto err_ps_input_register;
+ }
+
+ err = sysfs_create_group(&ps_data->als_input_dev->dev.kobj, &stk_als_attribute_group);
+ if (err < 0)
+ {
+ printk(KERN_ERR "%s:could not create sysfs group for als\n", __func__);
+ goto err_als_sysfs_create_group;
+ }
+ err = sysfs_create_group(&ps_data->ps_input_dev->dev.kobj, &stk_ps_attribute_group);
+ if (err < 0)
+ {
+ printk(KERN_ERR "%s:could not create sysfs group for ps\n", __func__);
+ goto err_ps_sysfs_create_group;
+ }
+ input_set_drvdata(ps_data->als_input_dev, ps_data);
+ input_set_drvdata(ps_data->ps_input_dev, ps_data);
+
+#ifdef STK_POLL_ALS
+ ps_data->stk_als_wq = create_singlethread_workqueue("stk_als_wq");
+ INIT_WORK(&ps_data->stk_als_work, stk_als_work_func);
+ hrtimer_init(&ps_data->als_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ ps_data->als_poll_delay = ns_to_ktime(110 * NSEC_PER_MSEC);
+ ps_data->als_timer.function = stk_als_timer_func;
+#endif
+
+ ps_data->stk_ps_wq = create_singlethread_workqueue("stk_ps_wq");
+ INIT_WORK(&ps_data->stk_ps_work, stk_ps_work_func);
+ hrtimer_init(&ps_data->ps_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ ps_data->ps_poll_delay = ns_to_ktime(110 * NSEC_PER_MSEC);
+ ps_data->ps_timer.function = stk_ps_timer_func;
+#if (!defined(STK_POLL_ALS) || !defined(STK_POLL_PS))
+ ps_data->stk_wq = create_singlethread_workqueue("stk_wq");
+ INIT_WORK(&ps_data->stk_work, stk_work_func);
+ err = stk3x1x_setup_irq(client);
+ if(err < 0)
+ goto err_stk3x1x_setup_irq;
+#endif
+
+ err = stk3x1x_init_all_setting(client, plat_data);
+ if(err < 0)
+ goto err_init_all_setting;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ ps_data->stk_early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ ps_data->stk_early_suspend.suspend = stk3x1x_early_suspend;
+ ps_data->stk_early_suspend.resume = stk3x1x_late_resume;
+ register_early_suspend(&ps_data->stk_early_suspend);
+#endif
+ printk(KERN_INFO "%s: probe successfully", __func__);
+ return 0;
+
+err_init_all_setting:
+#ifndef STK_POLL_PS
+ free_irq(ps_data->irq, ps_data);
+ gpio_free(plat_data->int_pin);
+#endif
+#if (!defined(STK_POLL_ALS) || !defined(STK_POLL_PS))
+err_stk3x1x_setup_irq:
+#endif
+#ifdef STK_POLL_ALS
+ hrtimer_try_to_cancel(&ps_data->als_timer);
+ destroy_workqueue(ps_data->stk_als_wq);
+#endif
+ destroy_workqueue(ps_data->stk_ps_wq);
+#if (!defined(STK_POLL_ALS) || !defined(STK_POLL_PS))
+ destroy_workqueue(ps_data->stk_wq);
+#endif
+ sysfs_remove_group(&ps_data->ps_input_dev->dev.kobj, &stk_ps_attribute_group);
+err_ps_sysfs_create_group:
+ sysfs_remove_group(&ps_data->als_input_dev->dev.kobj, &stk_als_attribute_group);
+err_als_sysfs_create_group:
+ input_unregister_device(ps_data->ps_input_dev);
+err_ps_input_register:
+ input_unregister_device(ps_data->als_input_dev);
+err_als_input_register:
+ input_free_device(ps_data->ps_input_dev);
+err_ps_input_allocate:
+ input_free_device(ps_data->als_input_dev);
+err_als_input_allocate:
+#ifdef STK_POLL_PS
+ wake_lock_destroy(&ps_data->ps_nosuspend_wl);
+#endif
+ wake_lock_destroy(&ps_data->ps_wakelock);
+ mutex_destroy(&ps_data->io_lock);
+ kfree(ps_data);
+ return err;
+}
+
+
+static int stk3x1x_remove(struct i2c_client *client)
+{
+ struct stk3x1x_data *ps_data = i2c_get_clientdata(client);
+#ifndef STK_POLL_PS
+ free_irq(ps_data->irq, ps_data);
+ gpio_free(ps_data->int_pin);
+#endif
+#ifdef STK_POLL_ALS
+ hrtimer_try_to_cancel(&ps_data->als_timer);
+ destroy_workqueue(ps_data->stk_als_wq);
+#endif
+ destroy_workqueue(ps_data->stk_ps_wq);
+#if (!defined(STK_POLL_ALS) || !defined(STK_POLL_PS))
+ destroy_workqueue(ps_data->stk_wq);
+#endif
+ sysfs_remove_group(&ps_data->ps_input_dev->dev.kobj, &stk_ps_attribute_group);
+ sysfs_remove_group(&ps_data->als_input_dev->dev.kobj, &stk_als_attribute_group);
+ input_unregister_device(ps_data->ps_input_dev);
+ input_unregister_device(ps_data->als_input_dev);
+ input_free_device(ps_data->ps_input_dev);
+ input_free_device(ps_data->als_input_dev);
+#ifdef STK_POLL_PS
+ wake_lock_destroy(&ps_data->ps_nosuspend_wl);
+#endif
+ wake_lock_destroy(&ps_data->ps_wakelock);
+ mutex_destroy(&ps_data->io_lock);
+ kfree(ps_data);
+
+ return 0;
+}
+
+static const struct i2c_device_id stk_ps_id[] =
+{
+ { "stk_ps", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, stk_ps_id);
+
+static struct i2c_driver stk_ps_driver =
+{
+ .driver = {
+ .name = DEVICE_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = stk3x1x_probe,
+ .remove = stk3x1x_remove,
+ .id_table = stk_ps_id,
+};
+
+
+static int __init stk3x1x_init(void)
+{
+ int ret;
+ ret = i2c_add_driver(&stk_ps_driver);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void __exit stk3x1x_exit(void)
+{
+ i2c_del_driver(&stk_ps_driver);
+}
+
+module_init(stk3x1x_init);
+module_exit(stk3x1x_exit);
+MODULE_AUTHOR("Lex Hsieh <lex_hsieh@sitronix.com.tw>");
+MODULE_DESCRIPTION("Sensortek stk3x1x Proximity Sensor driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c
index 25228a6..83b2aa1 100644
--- a/drivers/input/touchscreen/ft5x06_ts.c
+++ b/drivers/input/touchscreen/ft5x06_ts.c
@@ -76,12 +76,14 @@
#define FT_PMODE_HIBERNATE 0x03
#define FT_FACTORYMODE_VALUE 0x40
#define FT_WORKMODE_VALUE 0x00
-#define FT_RST_CMD_REG 0xFC
+#define FT_RST_CMD_REG1 0xFC
+#define FT_RST_CMD_REG2 0xBC
#define FT_READ_ID_REG 0x90
#define FT_ERASE_APP_REG 0x61
#define FT_ERASE_PANEL_REG 0x63
#define FT_FW_START_REG 0xBF
+#define FT_STATUS_NUM_TP_MASK 0x0F
#define FT_VTG_MIN_UV 2600000
#define FT_VTG_MAX_UV 3300000
@@ -97,6 +99,7 @@
#define FT5316_ID 0x0A
#define FT5306I_ID 0x55
+#define FT6X06_ID 0x06
#define FT_UPGRADE_AA 0xAA
#define FT_UPGRADE_55 0x55
@@ -133,6 +136,14 @@
#define FT6208_UPGRADE_READID_DELAY 10
#define FT6208_UPGRADE_EARSE_DELAY 2000
+/*upgrade config of FT6x06*/
+#define FT6X06_UPGRADE_AA_DELAY 100
+#define FT6X06_UPGRADE_55_DELAY 30
+#define FT6X06_UPGRADE_ID_1 0x79
+#define FT6X06_UPGRADE_ID_2 0x08
+#define FT6X06_UPGRADE_READID_DELAY 10
+#define FT6X06_UPGRADE_EARSE_DELAY 2000
+
#define FT_UPGRADE_INFO(x, y) do { \
x->delay_55 = y##_UPGRADE_55_DELAY; \
x->delay_aa = y##_UPGRADE_AA_DELAY; \
@@ -161,7 +172,7 @@
#define FT_FW_LAST_PKT 0x6ffa
#define FT_EARSE_DLY_MS 100
-#define FT_UPGRADE_LOOP 3
+#define FT_UPGRADE_LOOP 10
#define FT_CAL_START 0x04
#define FT_CAL_FIN 0x00
#define FT_CAL_STORE 0x05
@@ -329,6 +340,7 @@
static int ft5x06_handle_touchdata(struct ft5x06_ts_data *data)
{
struct ts_event *event = &data->event;
+ int num_points;
int ret, i;
u8 buf[POINT_READ_BUF] = { 0 };
u8 pointid = FT_MAX_ID;
@@ -342,7 +354,9 @@
memset(event, 0, sizeof(struct ts_event));
event->touch_point = 0;
- for (i = 0; i < CFG_MAX_TOUCH_POINTS; i++) {
+ num_points = buf[2] & FT_STATUS_NUM_TP_MASK;
+
+ for (i = 0; i < num_points; i++) {
pointid = (buf[FT_TOUCH_ID_POS + FT_TOUCH_STEP * i]) >> 4;
if (pointid >= FT_MAX_ID)
break;
@@ -575,6 +589,9 @@
msleep(FT_RESET_DLY);
gpio_set_value_cansleep(data->pdata->reset_gpio, 1);
}
+
+ msleep(FT_STARTUP_DLY);
+
enable_irq(data->client->irq);
data->suspended = false;
@@ -674,6 +691,9 @@
case FT5316_ID:
FT_UPGRADE_INFO(info, FT5316);
break;
+ case FT6X06_ID:
+ FT_UPGRADE_INFO(info, FT6X06);
+ break;
default:
return -EINVAL;
}
@@ -686,6 +706,7 @@
{
struct ft5x06_ts_data *ts_data = i2c_get_clientdata(client);
struct upgrade_info info;
+ u8 reset_reg;
u8 w_buf[FT_MAX_WR_BUF] = {0}, r_buf[FT_MAX_RD_BUF] = {0};
u8 pkt_buf[FT_FW_PKT_LEN + FT_FW_PKT_META_LEN];
int rc, i, j, temp;
@@ -698,22 +719,27 @@
return -EINVAL;
}
- for (i = 0; i < FT_UPGRADE_LOOP; i++) {
- /* reset - write 0xaa and 0x55 to register 0xfc */
- ft5x0x_write_reg(client, FT_RST_CMD_REG, FT_UPGRADE_AA);
+ for (i = 0, j = 0; i < FT_UPGRADE_LOOP; i++) {
+ /* reset - write 0xaa and 0x55 to reset register */
+ if (ts_data->family_id == FT6X06_ID)
+ reset_reg = FT_RST_CMD_REG2;
+ else
+ reset_reg = FT_RST_CMD_REG1;
+
+ ft5x0x_write_reg(client, reset_reg, FT_UPGRADE_AA);
msleep(info.delay_aa);
- ft5x0x_write_reg(client, FT_RST_CMD_REG, FT_UPGRADE_55);
+ ft5x0x_write_reg(client, reset_reg, FT_UPGRADE_55);
msleep(info.delay_55);
/* Enter upgrade mode */
w_buf[0] = FT_UPGRADE_55;
w_buf[1] = FT_UPGRADE_AA;
do {
- i++;
+ j++;
rc = ft5x06_i2c_write(client, w_buf, 2);
msleep(FT_RETRY_DLY);
- } while (rc <= 0 && i < FT_MAX_TRIES);
+ } while (rc <= 0 && j < FT_MAX_TRIES);
/* check READ_ID */
msleep(info.delay_readid);
@@ -816,6 +842,8 @@
ft5x06_i2c_write(client, w_buf, 1);
msleep(FT_STARTUP_DLY);
+ dev_info(&client->dev, "Firmware upgrade successful\n");
+
return 0;
}
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index 908d0d7..ba0be2b 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -1056,8 +1056,6 @@
rmi4_pdata->i2c_pull_up = of_property_read_bool(np,
"synaptics,i2c-pull-up");
- rmi4_pdata->power_down_enable = of_property_read_bool(np,
- "synaptics,power-down");
rmi4_pdata->x_flip = of_property_read_bool(np, "synaptics,x-flip");
rmi4_pdata->y_flip = of_property_read_bool(np, "synaptics,y-flip");
@@ -2005,7 +2003,7 @@
error_reg_en_vcc_i2c:
if (rmi4_data->board->i2c_pull_up)
- reg_set_optimum_mode_check(rmi4_data->vcc_i2c, 0);
+ reg_set_optimum_mode_check(rmi4_data->vdd, 0);
error_reg_opt_i2c:
regulator_disable(rmi4_data->vdd);
error_reg_en_vdd:
@@ -2594,51 +2592,27 @@
bool on)
{
int retval;
- int load_ua;
if (on == false)
goto regulator_hpm;
- load_ua = rmi4_data->board->power_down_enable ? 0 : RMI4_LPM_LOAD_UA;
- retval = reg_set_optimum_mode_check(rmi4_data->vdd, load_ua);
+ retval = reg_set_optimum_mode_check(rmi4_data->vdd, RMI4_LPM_LOAD_UA);
if (retval < 0) {
dev_err(&rmi4_data->i2c_client->dev,
- "Regulator vdd_ana set_opt failed rc=%d\n",
+ "Regulator vcc_ana set_opt failed rc=%d\n",
retval);
goto fail_regulator_lpm;
}
- if (rmi4_data->board->power_down_enable) {
- retval = regulator_disable(rmi4_data->vdd);
- if (retval) {
- dev_err(&rmi4_data->i2c_client->dev,
- "Regulator vdd disable failed rc=%d\n",
- retval);
- goto fail_regulator_lpm;
- }
- }
-
if (rmi4_data->board->i2c_pull_up) {
- load_ua = rmi4_data->board->power_down_enable ?
- 0 : RMI4_I2C_LPM_LOAD_UA;
retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
- load_ua);
+ RMI4_I2C_LPM_LOAD_UA);
if (retval < 0) {
dev_err(&rmi4_data->i2c_client->dev,
- "Regulator vcc_i2c set_opt failed " \
- "rc=%d\n", retval);
+ "Regulator vcc_i2c set_opt failed rc=%d\n",
+ retval);
goto fail_regulator_lpm;
}
-
- if (rmi4_data->board->power_down_enable) {
- retval = regulator_disable(rmi4_data->vcc_i2c);
- if (retval) {
- dev_err(&rmi4_data->i2c_client->dev,
- "Regulator vcc_i2c disable failed " \
- "rc=%d\n", retval);
- goto fail_regulator_lpm;
- }
- }
}
return 0;
@@ -2654,16 +2628,6 @@
goto fail_regulator_hpm;
}
- if (rmi4_data->board->power_down_enable) {
- retval = regulator_enable(rmi4_data->vdd);
- if (retval) {
- dev_err(&rmi4_data->i2c_client->dev,
- "Regulator vdd enable failed rc=%d\n",
- retval);
- goto fail_regulator_hpm;
- }
- }
-
if (rmi4_data->board->i2c_pull_up) {
retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
RMI4_I2C_LOAD_UA);
@@ -2673,26 +2637,6 @@
retval);
goto fail_regulator_hpm;
}
-
- if (rmi4_data->board->power_down_enable) {
- retval = regulator_enable(rmi4_data->vcc_i2c);
- if (retval) {
- dev_err(&rmi4_data->i2c_client->dev,
- "Regulator vcc_i2c enable failed " \
- "rc=%d\n", retval);
- goto fail_regulator_hpm;
- }
- }
- }
-
- if (rmi4_data->board->power_down_enable) {
- retval = synaptics_rmi4_reset_device(rmi4_data);
- if (retval < 0) {
- dev_err(&rmi4_data->i2c_client->dev,
- "%s: Failed to issue reset command, rc = %d\n",
- __func__, retval);
- return retval;
- }
}
return 0;
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index bdc476e..b896f65 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -43,7 +43,7 @@
#define WLED_HIGH_POLE_CAP_REG(base) (base + 0x58)
#define WLED_CURR_SINK_MASK 0xE0
#define WLED_CURR_SINK_SHFT 0x05
-#define WLED_SWITCH_FREQ_MASK 0x02
+#define WLED_SWITCH_FREQ_MASK 0x0F
#define WLED_OVP_VAL_MASK 0x03
#define WLED_OVP_VAL_BIT_SHFT 0x00
#define WLED_BOOST_LIMIT_MASK 0x07
@@ -78,7 +78,7 @@
#define WLED_BOOST_LIM_DEFAULT 0x03
#define WLED_CP_SEL_DEFAULT 0x00
#define WLED_CTRL_DLY_DEFAULT 0x00
-#define WLED_SWITCH_FREQ_DEFAULT 0x02
+#define WLED_SWITCH_FREQ_DEFAULT 0x0B
#define FLASH_SAFETY_TIMER(base) (base + 0x40)
#define FLASH_MAX_CURR(base) (base + 0x41)
@@ -239,14 +239,6 @@
WLED_OVP_37V,
};
-/* switch frquency */
-enum wled_switch_freq {
- WLED_800kHz = 0,
- WLED_960kHz,
- WLED_1600kHz,
- WLED_3200kHz,
-};
-
enum flash_headroom {
HEADROOM_250mV = 0,
HEADROOM_300mV,
@@ -1312,11 +1304,12 @@
}
/* program switch frequency */
- rc = qpnp_led_masked_write(led, WLED_SWITCHING_FREQ_REG(led->base),
+ rc = qpnp_led_masked_write(led,
+ WLED_SWITCHING_FREQ_REG(led->base),
WLED_SWITCH_FREQ_MASK, led->wled_cfg->switch_freq);
if (rc) {
dev_err(&led->spmi_dev->dev,
- "WLED switch freq reg write failed(%d)\n", rc);
+ "WLED switch freq reg write failed(%d)\n", rc);
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index 3722066..aac973e 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -144,7 +144,7 @@
/* CGC_OVERRIDE */
msm_camera_io_w(0x07FFFFFF, vfe_dev->vfe_base + 0xC);
/* BUS_CFG */
- msm_camera_io_w(0x00000001, vfe_dev->vfe_base + 0x3C);
+ msm_camera_io_w(0x00000009, vfe_dev->vfe_base + 0x3C);
msm_camera_io_w(0x01000025, vfe_dev->vfe_base + 0x1C);
msm_camera_io_w_mb(0x1CFFFFFF, vfe_dev->vfe_base + 0x20);
msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x24);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index d857a14..33f63b3 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -150,6 +150,12 @@
stats_idx = vfe_dev->hw_info->vfe_ops.stats_ops.
get_stats_idx(stream_req_cmd->stats_type);
+ if ((stats_idx > MSM_ISP_STATS_MAX) ||
+ (stats_idx == -EINVAL)) {
+ pr_err("%s: Stats idx Error\n", __func__);
+ return rc;
+ }
+
stream_info = &stats_data->stream_info[stats_idx];
if (stream_info->state != STATS_AVALIABLE) {
pr_err("%s: Stats already requested\n", __func__);
@@ -188,7 +194,7 @@
int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg)
{
- int rc = 0;
+ int rc = -1;
struct msm_vfe_stats_stream_request_cmd *stream_req_cmd = arg;
struct msm_vfe_stats_stream *stream_info = NULL;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
@@ -202,6 +208,11 @@
}
stats_idx = STATS_IDX(stream_req_cmd->stream_handle);
+ if (stats_idx > MSM_ISP_STATS_MAX) {
+ pr_err("%s: Stats idx Error\n", __func__);
+ return rc;
+ }
+
stream_info = &stats_data->stream_info[stats_idx];
framedrop_period = msm_isp_get_framedrop_period(
@@ -228,9 +239,14 @@
struct msm_vfe_stats_stream_release_cmd *stream_release_cmd = arg;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
int stats_idx = STATS_IDX(stream_release_cmd->stream_handle);
- struct msm_vfe_stats_stream *stream_info =
- &stats_data->stream_info[stats_idx];
+ struct msm_vfe_stats_stream *stream_info = NULL;
+ if (stats_idx > MSM_ISP_STATS_MAX) {
+ pr_err("%s: Stats idx Error\n", __func__);
+ return rc;
+ }
+
+ stream_info = &stats_data->stream_info[stats_idx];
if (stream_info->state == STATS_AVALIABLE) {
pr_err("%s: stream already release\n", __func__);
return rc;
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index 3082e99..2f6e6a7 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -18,6 +18,7 @@
#include <linux/videodev2.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
+#include <linux/iopoll.h>
#include <media/msmb_isp.h>
#include "msm_ispif.h"
@@ -38,6 +39,9 @@
#define ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY 0x01
#define ISPIF_INTF_CMD_DISABLE_IMMEDIATELY 0x02
+#define ISPIF_TIMEOUT_SLEEP_US 1000
+#define ISPIF_TIMEOUT_ALL_US 500000
+
#undef CDBG
#ifdef CONFIG_MSMB_CAMERA_DEBUG
#define CDBG(fmt, args...) pr_debug(fmt, ##args)
@@ -63,6 +67,78 @@
{"ispif_ahb_clk", -1},
};
+static struct msm_cam_clk_info ispif_8974_reset_clk_info[] = {
+ {"csi0_src_clk", INIT_RATE},
+ {"csi0_clk", NO_SET_RATE},
+ {"csi0_pix_clk", NO_SET_RATE},
+ {"csi0_rdi_clk", NO_SET_RATE},
+ {"vfe0_clk_src", INIT_RATE},
+ {"camss_vfe_vfe0_clk", NO_SET_RATE},
+ {"camss_csi_vfe0_clk", NO_SET_RATE},
+ {"vfe1_clk_src", INIT_RATE},
+ {"camss_vfe_vfe1_clk", NO_SET_RATE},
+ {"camss_csi_vfe1_clk", NO_SET_RATE},
+};
+
+static int msm_ispif_reset_hw(struct ispif_device *ispif)
+{
+ int rc = 0;
+ long timeout = 0;
+ struct clk *reset_clk[ARRAY_SIZE(ispif_8974_reset_clk_info)];
+
+ if (ispif->csid_version < CSID_VERSION_V30) {
+ /* currently reset is done only for 8974 */
+ return 0;
+ }
+
+ rc = msm_cam_clk_enable(&ispif->pdev->dev,
+ ispif_8974_reset_clk_info, reset_clk,
+ ARRAY_SIZE(ispif_8974_reset_clk_info), 1);
+ if (rc < 0) {
+ pr_err("%s: cannot enable clock, error = %d",
+ __func__, rc);
+ }
+
+ init_completion(&ispif->reset_complete[VFE0]);
+ if (ispif->hw_num_isps > 1)
+ init_completion(&ispif->reset_complete[VFE1]);
+
+ /* initiate reset of ISPIF */
+ msm_camera_io_w(ISPIF_RST_CMD_MASK,
+ ispif->base + ISPIF_RST_CMD_ADDR);
+ if (ispif->hw_num_isps > 1)
+ msm_camera_io_w(ISPIF_RST_CMD_1_MASK,
+ ispif->base + ISPIF_RST_CMD_1_ADDR);
+
+ timeout = wait_for_completion_interruptible_timeout(
+ &ispif->reset_complete[VFE0], msecs_to_jiffies(500));
+ CDBG("%s: VFE0 done\n", __func__);
+ if (timeout <= 0) {
+ pr_err("%s: VFE0 reset wait timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ if (ispif->hw_num_isps > 1) {
+ timeout = wait_for_completion_interruptible_timeout(
+ &ispif->reset_complete[VFE1],
+ msecs_to_jiffies(500));
+ CDBG("%s: VFE1 done\n", __func__);
+ if (timeout <= 0) {
+ pr_err("%s: VFE1 reset wait timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+ }
+
+ rc = msm_cam_clk_enable(&ispif->pdev->dev,
+ ispif_8974_reset_clk_info, reset_clk,
+ ARRAY_SIZE(ispif_8974_reset_clk_info), 0);
+ if (rc < 0) {
+ pr_err("%s: cannot disable clock, error = %d",
+ __func__, rc);
+ }
+ return rc;
+}
+
static int msm_ispif_clk_ahb_enable(struct ispif_device *ispif, int enable)
{
int rc = 0;
@@ -573,6 +649,7 @@
uint16_t cid_mask = 0;
uint32_t intf_addr;
enum msm_ispif_vfe_intf vfe_intf;
+ uint32_t stop_flag = 0;
BUG_ON(!ispif);
BUG_ON(!params);
@@ -625,10 +702,12 @@
goto end;
}
- /* todo_bug_fix? very bad. use readl_poll_timeout */
- while ((msm_camera_io_r(ispif->base + intf_addr) & 0xF) != 0xF)
- CDBG("%s: Wait for %d Idle\n", __func__,
- params->entries[i].intftype);
+ rc = readl_poll_timeout(ispif->base + intf_addr, stop_flag,
+ (stop_flag & 0xF) == 0xF,
+ ISPIF_TIMEOUT_SLEEP_US,
+ ISPIF_TIMEOUT_ALL_US);
+ if (rc < 0)
+ goto end;
/* disable CIDs in CID_MASK register */
msm_ispif_enable_intf_cids(ispif, params->entries[i].intftype,
@@ -706,6 +785,9 @@
ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
if (out[VFE0].ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) {
+ if (out[VFE0].ispifIrqStatus0 & RESET_DONE_IRQ)
+ complete(&ispif->reset_complete[VFE0]);
+
if (out[VFE0].ispifIrqStatus0 & PIX_INTF_0_OVERFLOW_IRQ)
pr_err("%s: VFE0 pix0 overflow.\n", __func__);
@@ -721,6 +803,9 @@
ispif_process_irq(ispif, out, VFE0);
}
if (ispif->vfe_info.num_vfe > 1) {
+ if (out[VFE1].ispifIrqStatus0 & RESET_DONE_IRQ)
+ complete(&ispif->reset_complete[VFE1]);
+
if (out[VFE1].ispifIrqStatus0 & PIX_INTF_0_OVERFLOW_IRQ)
pr_err("%s: VFE1 pix0 overflow.\n", __func__);
@@ -811,7 +896,7 @@
pr_err("%s: ahb_clk enable failed", __func__);
goto error_ahb;
}
-
+ msm_ispif_reset_hw(ispif);
rc = msm_ispif_reset(ispif);
if (rc == 0) {
ispif->ispif_state = ISPIF_POWER_UP;
@@ -1002,9 +1087,18 @@
goto error_sd_register;
}
- if (pdev->dev.of_node)
+
+ if (pdev->dev.of_node) {
of_property_read_u32((&pdev->dev)->of_node,
"cell-index", &pdev->id);
+ rc = of_property_read_u32((&pdev->dev)->of_node,
+ "qcom,num-isps", &ispif->hw_num_isps);
+ if (rc)
+ /* backward compatibility */
+ ispif->hw_num_isps = 1;
+ /* not an error condition */
+ rc = 0;
+ }
ispif->mem = platform_get_resource_byname(pdev,
IORESOURCE_MEM, "ispif");
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
index faa32aa..45e7354 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
@@ -58,5 +58,7 @@
enum msm_ispif_state_t ispif_state;
struct msm_ispif_vfe_info vfe_info;
struct clk *ahb_clk;
+ struct completion reset_complete[VFE_MAX];
+ uint32_t hw_num_isps;
};
#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c
index c2a5cad..6bd7feb 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c
@@ -140,6 +140,7 @@
{
int i;
int rc = 0;
+ long clk_rate;
if (enable) {
for (i = 0; i < num_clk; i++) {
CDBG("%s enable %s\n", __func__,
@@ -158,6 +159,24 @@
clk_info[i].clk_name);
goto cam_clk_set_err;
}
+ } else if (clk_info[i].clk_rate == INIT_RATE) {
+ clk_rate = clk_get_rate(clk_ptr[i]);
+ if (clk_rate == 0) {
+ clk_rate =
+ clk_round_rate(clk_ptr[i], 0);
+ if (clk_rate < 0) {
+ pr_err("%s round rate failed\n",
+ clk_info[i].clk_name);
+ goto cam_clk_set_err;
+ }
+ rc = clk_set_rate(clk_ptr[i],
+ clk_rate);
+ if (rc < 0) {
+ pr_err("%s set rate failed\n",
+ clk_info[i].clk_name);
+ goto cam_clk_set_err;
+ }
+ }
}
rc = clk_prepare(clk_ptr[i]);
if (rc < 0) {
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.h b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.h
index 73376e2..2e6f809 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.h
@@ -18,6 +18,9 @@
#include <mach/camera2.h>
#include <media/msm_cam_sensor.h>
+#define NO_SET_RATE -1
+#define INIT_RATE -2
+
void msm_camera_io_w(u32 data, void __iomem *addr);
void msm_camera_io_w_mb(u32 data, void __iomem *addr);
u32 msm_camera_io_r(void __iomem *addr);
diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c
index 79a492e..5140a03 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.c
+++ b/drivers/media/platform/msm/vidc/msm_smem.c
@@ -500,8 +500,13 @@
struct smem_client *client = clt;
struct iommu_set *iommu_group_set = &client->res->iommu_group_set;
int i;
+ int j;
bool is_secure = (flags & SMEM_SECURE);
struct iommu_info *iommu_map;
+ if (!domain_num || !partition_num) {
+ dprintk(VIDC_DBG, "passed null to get domain partition!");
+ return -EINVAL;
+ }
*domain_num = -1;
*partition_num = -1;
@@ -512,14 +517,14 @@
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;
+ if (iommu_map->is_secure == is_secure) {
+ for (j = 0; j < iommu_map->npartitions; j++) {
+ if (iommu_map->buffer_type[j] & buffer_type) {
+ *domain_num = iommu_map->domain;
+ *partition_num = j;
+ break;
+ }
+ }
}
}
dprintk(VIDC_DBG, "domain: %d, partition: %d found!\n",
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index ad34d45..f94b6f1 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -770,12 +770,12 @@
vb->v4l2_planes[0].bytesused = response->input_done.filled_len;
vb->v4l2_planes[0].data_offset = response->input_done.offset;
if (vb->v4l2_planes[0].data_offset > vb->v4l2_planes[0].length)
- dprintk(VIDC_ERR, "Error: data_offset overflow\n");
+ dprintk(VIDC_INFO, "data_offset overflow length\n");
if (vb->v4l2_planes[0].bytesused > vb->v4l2_planes[0].length)
- dprintk(VIDC_ERR, "Error: buffer overflow\n");
+ dprintk(VIDC_INFO, "bytesused overflow length\n");
if ((u8 *)vb->v4l2_planes[0].m.userptr !=
response->input_done.packet_buffer)
- dprintk(VIDC_ERR, "Error: unexpected buffer address\n");
+ dprintk(VIDC_INFO, "Unexpected buffer address\n");
vb->v4l2_buf.flags = 0;
empty_buf_done = (struct vidc_hal_ebd *)&response->input_done;
if (empty_buf_done) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
index cb08da7..394ecdc5 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
@@ -386,65 +386,56 @@
{
int rc = 0;
struct platform_device *pdev = res->pdev;
- struct device_node *ctx_node;
+ struct device_node *domains_parent_node = NULL;
+ struct device_node *domains_child_node = NULL;
struct iommu_set *iommu_group_set = &res->iommu_group_set;
- int array_size;
- int i;
+ int domain_idx = 0;
struct iommu_info *iommu_map;
- u32 *buffer_types = NULL;
+ int array_size = 0;
- if (!of_get_property(pdev->dev.of_node, "qcom,iommu-groups",
- &array_size)) {
- dprintk(VIDC_DBG, "iommu_groups property not present\n");
- iommu_group_set->count = 0;
+ domains_parent_node = of_find_node_by_name(pdev->dev.of_node,
+ "qcom,vidc-iommu-domains");
+ if (!domains_parent_node) {
+ dprintk(VIDC_DBG, "Node qcom,vidc-iommu-domains not found.\n");
return 0;
}
- iommu_group_set->count = array_size / sizeof(u32);
+ iommu_group_set->count = 0;
+ for_each_child_of_node(domains_parent_node, domains_child_node) {
+ iommu_group_set->count++;
+ }
+
if (iommu_group_set->count == 0) {
- dprintk(VIDC_ERR, "No group present in iommu_groups\n");
+ dprintk(VIDC_ERR, "No group present in iommu_domains\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__);
+ dprintk(VIDC_ERR, "Cannot allocate iommu_maps\n");
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;
- }
+ /* set up each context bank */
+ for_each_child_of_node(domains_parent_node, domains_child_node) {
+ struct device_node *ctx_node = of_parse_phandle(
+ domains_child_node,
+ "qcom,vidc-domain-phandle",
+ 0);
+ if (domain_idx >= iommu_group_set->count)
+ break;
- 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);
+ iommu_map = &iommu_group_set->iommu_maps[domain_idx];
if (!ctx_node) {
- dprintk(VIDC_ERR, "Unable to parse phandle : %u\n", i);
+ dprintk(VIDC_ERR, "Unable to parse pHandle\n");
rc = -EBADHANDLE;
goto err_load_groups;
}
+ /* domain info from domains.dtsi */
rc = of_property_read_string(ctx_node, "label",
&(iommu_map->name));
if (rc) {
@@ -452,6 +443,11 @@
goto err_load_groups;
}
+ dprintk(VIDC_DBG,
+ "domain %d has name %s\n",
+ domain_idx,
+ iommu_map->name);
+
if (!of_get_property(ctx_node, "qcom,virtual-addr-pool",
&array_size)) {
dprintk(VIDC_ERR,
@@ -463,25 +459,48 @@
iommu_map->npartitions = array_size / sizeof(u32) / 2;
+ dprintk(VIDC_DBG,
+ "%d partitions in domain %d",
+ iommu_map->npartitions,
+ domain_idx);
+
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);
+ "Could not read addr pool for group : %s (%d)\n",
+ iommu_map->name,
+ rc);
goto err_load_groups;
}
- iommu_map->buffer_type = buffer_types[i];
iommu_map->is_secure =
of_property_read_bool(ctx_node, "qcom,secure-domain");
+
+ dprintk(VIDC_DBG,
+ "domain %s : secure = %d",
+ iommu_map->name,
+ iommu_map->is_secure);
+
+ /* setup partitions and buffer type per partition */
+ rc = of_property_read_u32_array(domains_child_node,
+ "qcom,vidc-partition-buffer-types",
+ iommu_map->buffer_type,
+ iommu_map->npartitions);
+
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "cannot load partition buffertype information (%d)",
+ rc);
+ rc = -ENOENT;
+ goto err_load_groups;
+ }
+ domain_idx++;
}
- kfree(buffer_types);
- return 0;
+ return rc;
err_load_groups:
- kfree(buffer_types);
msm_vidc_free_iommu_groups(res);
err_no_of_node:
return rc;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
index 43af909..8176ea5 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
@@ -16,6 +16,7 @@
#include <linux/platform_device.h>
#include <media/msm_vidc.h>
+#define MAX_BUFFER_TYPES 32
struct load_freq_table {
u32 load;
@@ -39,11 +40,11 @@
struct iommu_info {
const char *name;
- u32 buffer_type;
+ u32 buffer_type[MAX_BUFFER_TYPES];
struct iommu_group *group;
int domain;
bool is_secure;
- struct addr_range addr_range[2];
+ struct addr_range addr_range[MAX_BUFFER_TYPES];
int npartitions;
};
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 47b88db..5416210 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -2804,6 +2804,9 @@
iommu_map->addr_range[0].start;
memprot.cp_nonpixel_size =
iommu_map->addr_range[0].size;
+ } else if (strcmp(iommu_map->name, "venus_cp") == 0) {
+ memprot.cp_nonpixel_start =
+ iommu_map->addr_range[1].start;
}
}
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 3d0abce..1eebe61 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -470,7 +470,7 @@
found = wcd9xxx_check_codec_type(wcd9xxx, &version);
if (!found) {
ret = -ENODEV;
- goto err_irq;
+ goto err;
} else {
wcd9xxx->codec_type = found;
wcd9xxx->version = version;
diff --git a/drivers/misc/qpnp-misc.c b/drivers/misc/qpnp-misc.c
index 608be81..6ad4816 100644
--- a/drivers/misc/qpnp-misc.c
+++ b/drivers/misc/qpnp-misc.c
@@ -21,7 +21,8 @@
#define QPNP_MISC_DEV_NAME "qcom,qpnp-misc"
-#define REVID_REVISION2 0x1
+#define REG_DIG_MAJOR_REV 0x01
+#define REG_SUBTYPE 0x05
static DEFINE_MUTEX(qpnp_misc_dev_list_mutex);
static LIST_HEAD(qpnp_misc_dev_list);
@@ -45,6 +46,11 @@
struct spmi_device *spmi;
};
+struct qpnp_misc_version {
+ u8 subtype;
+ u8 dig_major_rev;
+};
+
static struct of_device_id qpnp_misc_match_table[] = {
{ .compatible = QPNP_MISC_DEV_NAME },
{}
@@ -63,17 +69,28 @@
return val;
}
-#define REV2_IRQ_AVAILABLE_VERSION 2
+static struct qpnp_misc_version irq_support_version[] = {
+ {0x01, 0x02}, /* PM8941 */
+ {0x07, 0x00}, /* PM8226 */
+ {0x09, 0x00}, /* PMA8084 */
+};
+
static bool __misc_irqs_available(struct qpnp_misc_dev *dev)
{
- u8 rev2;
+ int i;
+ u8 subtype, dig_major_rev;
- rev2 = qpnp_read_byte(dev->spmi,
- dev->resource->start + REVID_REVISION2);
- pr_debug("rev2 0x%x\n", rev2);
+ subtype = qpnp_read_byte(dev->spmi, dev->resource->start + REG_SUBTYPE);
+ pr_debug("subtype = 0x%02X\n", subtype);
- if (rev2 >= REV2_IRQ_AVAILABLE_VERSION)
- return 1;
+ dig_major_rev = qpnp_read_byte(dev->spmi,
+ dev->resource->start + REG_DIG_MAJOR_REV);
+ pr_debug("dig_major rev = 0x%02X\n", dig_major_rev);
+
+ for (i = 0; i < ARRAY_SIZE(irq_support_version); i++)
+ if (subtype == irq_support_version[i].subtype
+ && dig_major_rev >= irq_support_version[i].dig_major_rev)
+ return 1;
return 0;
}
@@ -84,6 +101,11 @@
struct qpnp_misc_dev *mdev = NULL;
struct qpnp_misc_dev *mdev_found = NULL;
+ if (IS_ERR_OR_NULL(consumer_dev)) {
+ pr_err("Invalid consumer device pointer\n");
+ return -EINVAL;
+ }
+
misc_node = of_parse_phandle(consumer_dev->of_node, "qcom,misc-ref", 0);
if (!misc_node) {
pr_debug("Could not find qcom,misc-ref property in %s\n",
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index b750602..0987b6b 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -890,8 +890,8 @@
data->type = QSEECOM_SECURE_SERVICE;
switch (req.cmd_id) {
- case QSEE_RPMB_PROVISION_KEY_COMMAND:
- case QSEE_RPMB_ERASE_COMMAND:
+ case QSEOS_RPMB_PROVISION_KEY_COMMAND:
+ case QSEOS_RPMB_ERASE_COMMAND:
if (__qseecom_process_rpmb_svc_cmd(data, &req,
&send_svc_ireq))
return -EINVAL;
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index a990f43..b140510 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -416,7 +416,7 @@
if (ret)
pr_err("%s: %s: failed setting runtime active: ret: %d\n",
mmc_hostname(card->host), __func__, ret);
- else
+ else if (!mmc_card_sdio(card))
pm_runtime_enable(&card->dev);
}
@@ -424,7 +424,7 @@
if (ret)
return ret;
- if (mmc_use_core_runtime_pm(card->host)) {
+ if (mmc_use_core_runtime_pm(card->host) && !mmc_card_sdio(card)) {
card->rpm_attrib.show = show_rpm_delay;
card->rpm_attrib.store = store_rpm_delay;
sysfs_attr_init(&card->rpm_attrib.attr);
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 3495f4d..96f8f2e 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -2472,6 +2472,7 @@
msm_host->mmc->caps2 |= MMC_CAP2_CLK_SCALE;
msm_host->mmc->caps2 |= MMC_CAP2_STOP_REQUEST;
msm_host->mmc->caps2 |= MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE;
+ msm_host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
if (msm_host->pdata->nonremovable)
msm_host->mmc->caps |= MMC_CAP_NONREMOVABLE;
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index efb78e5..e6493b1 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -1,6 +1,10 @@
#
# Makefile for the MSM specific device drivers.
#
+
+ccflags-y += -Idrivers/misc/
+
+
obj-$(CONFIG_MSM_SSBI) += ssbi.o
obj-$(CONFIG_USB_BAM) += usb_bam.o
obj-$(CONFIG_IPA) += ipa/
diff --git a/drivers/platform/msm/qpnp-revid.c b/drivers/platform/msm/qpnp-revid.c
index 897dc2a..9471188 100644
--- a/drivers/platform/msm/qpnp-revid.c
+++ b/drivers/platform/msm/qpnp-revid.c
@@ -30,7 +30,10 @@
"PM8841",
"PM8019",
"PM8226",
- "PM8110"
+ "PM8110",
+ "PMA8084",
+ "PMI8962",
+ "PMD9635",
};
static struct of_device_id qpnp_revid_match_table[] = {
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 6ccfd29..4f10cf8 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -81,6 +81,7 @@
u32 d_type;
bool enhd_pipe;
+bool imem;
static void sps_device_de_init(void);
@@ -2430,13 +2431,16 @@
resource = platform_get_resource(pdev, IORESOURCE_MEM, 2);
if (resource) {
+ imem = true;
sps->pipemem_phys_base = resource->start;
sps->pipemem_size = resource_size(resource);
SPS_DBG("sps:pipemem.base=0x%x,size=0x%x.",
sps->pipemem_phys_base,
sps->pipemem_size);
- } else
+ } else {
+ imem = false;
SPS_DBG("sps:No pipe memory on this target.\n");
+ }
resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (resource) {
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index d972e7b..bd4328a 100644
--- a/drivers/platform/msm/sps/sps_bam.c
+++ b/drivers/platform/msm/sps/sps_bam.c
@@ -445,6 +445,10 @@
if ((dev->props.manage & SPS_BAM_MGR_DEVICE_REMOTE)) {
/* No, so just mark it disabled */
dev->state &= ~BAM_STATE_ENABLED;
+ if ((dev->state & BAM_STATE_IRQ) && (dev->props.irq > 0)) {
+ free_irq(dev->props.irq, dev);
+ dev->state &= ~BAM_STATE_IRQ;
+ }
return 0;
}
diff --git a/drivers/platform/msm/sps/sps_mem.c b/drivers/platform/msm/sps/sps_mem.c
index faa1618..34a2001 100644
--- a/drivers/platform/msm/sps/sps_mem.c
+++ b/drivers/platform/msm/sps/sps_mem.c
@@ -109,7 +109,7 @@
/* 2^8=128. The desc-fifo and data-fifo minimal allocation. */
int min_alloc_order = 8;
- if ((d_type == 0) || (d_type == 2)) {
+ if ((d_type == 0) || (d_type == 2) || imem) {
iomem_phys = pipemem_phys_base;
iomem_size = pipemem_size;
@@ -136,7 +136,7 @@
return -ENOMEM;
}
- if ((d_type == 0) || (d_type == 2)) {
+ if ((d_type == 0) || (d_type == 2) || imem) {
res = gen_pool_add(pool, (u32) iomem_virt, iomem_size, nid);
if (res)
return res;
diff --git a/drivers/platform/msm/sps/spsi.h b/drivers/platform/msm/sps/spsi.h
index f65fef7..353ece6 100644
--- a/drivers/platform/msm/sps/spsi.h
+++ b/drivers/platform/msm/sps/spsi.h
@@ -50,6 +50,7 @@
extern u32 d_type;
extern bool enhd_pipe;
+extern bool imem;
#ifdef CONFIG_DEBUG_FS
extern u8 debugfs_record_enabled;
diff --git a/drivers/platform/msm/ssm.c b/drivers/platform/msm/ssm.c
index 3afb954..1544b14 100644
--- a/drivers/platform/msm/ssm.c
+++ b/drivers/platform/msm/ssm.c
@@ -23,7 +23,6 @@
#include <linux/mutex.h>
#include <linux/ion.h>
#include <linux/types.h>
-#include <linux/firmware.h>
#include <linux/elf.h>
#include <linux/platform_device.h>
#include <linux/msm_ion.h>
@@ -31,45 +30,33 @@
#include <mach/scm.h>
#include <mach/msm_smd.h>
+#include "qseecom_kernel.h"
#include "ssm.h"
/* Macros */
#define SSM_DEV_NAME "ssm"
#define MPSS_SUBSYS 0
#define SSM_INFO_CMD_ID 1
-#define QSEOS_CHECK_VERSION_CMD 0x00001803
-
#define MAX_APP_NAME_SIZE 32
-#define SSM_MSG_LEN (104 + 4) /* bytes + pad */
+#define SSM_MSG_LEN 200
#define SSM_MSG_FIELD_LEN 11
-#define SSM_HEADER_LEN (SSM_MSG_FIELD_LEN * 4)
-#define ATOM_MSG_LEN (SSM_HEADER_LEN + SSM_MSG_LEN)
-#define FIRMWARE_NAME "ssmapp"
-#define TZAPP_NAME "SsmApp"
-#define CHANNEL_NAME "SSM_RTR"
+#define ATOM_MSG_LEN (SSM_MSG_FIELD_LEN + SSM_MSG_LEN + 40)
-#define ALIGN_BUFFER(size) ((size + 4095) & ~4095)
+#define TZAPP_NAME "SsmApp"
+#define CHANNEL_NAME "SSM_RTR_MODEM_APPS"
/* SSM driver structure.*/
struct ssm_driver {
- int32_t app_id;
int32_t app_status;
int32_t update_status;
- int32_t atom_replay;
- int32_t mtoa_replay;
- uint32_t buff_len;
unsigned char *channel_name;
unsigned char *smd_buffer;
- struct ion_client *ssm_ion_client;
- struct ion_handle *ssm_ion_handle;
- struct tzapp_get_mode_info_rsp *resp;
struct device *dev;
smd_channel_t *ch;
- ion_phys_addr_t buff_phys;
- void *buff_virt;
- dev_t ssm_device_no;
struct work_struct ipc_work;
struct mutex mutex;
+ struct qseecom_handle *qseecom_handle;
+ struct tzapp_get_mode_info_rsp *resp;
bool key_status;
bool ready;
};
@@ -87,32 +74,45 @@
}
/*
+ * Setup CMD/RSP pointers.
+ */
+static void setup_cmd_rsp_buffers(struct qseecom_handle *handle, void **cmd,
+ int *cmd_len, void **resp, int *resp_len)
+{
+ *cmd = handle->sbuf;
+ if (*cmd_len & QSEECOM_ALIGN_MASK)
+ *cmd_len = QSEECOM_ALIGN(*cmd_len);
+
+ *resp = handle->sbuf + *cmd_len;
+ if (*resp_len & QSEECOM_ALIGN_MASK)
+ *resp_len = QSEECOM_ALIGN(*resp_len);
+}
+
+/*
* Send packet to modem over SMD channel.
*/
static int update_modem(enum ssm_ipc_req ipc_req, struct ssm_driver *ssm,
int length, char *data)
{
- unsigned int packet_len = SSM_HEADER_LEN + length + 1;
- int rc = 0;
+ unsigned int packet_len = length + SSM_MSG_FIELD_LEN;
+ int rc = 0, count;
- ssm->atom_replay += 1;
- snprintf(ssm->smd_buffer, SSM_HEADER_LEN + 1, "%10u|%10u|%10u|%10u|"
- , packet_len, ssm->atom_replay, ipc_req, length);
- memcpy(ssm->smd_buffer + SSM_HEADER_LEN, data, length);
-
- ssm->smd_buffer[packet_len - 1] = '|';
+ snprintf(ssm->smd_buffer, SSM_MSG_FIELD_LEN + 1, "%10u|", ipc_req);
+ memcpy(ssm->smd_buffer + SSM_MSG_FIELD_LEN, data, length);
if (smd_write_avail(ssm->ch) < packet_len) {
dev_err(ssm->dev, "Not enough space dropping request\n");
rc = -ENOSPC;
+ goto out;
}
- rc = smd_write(ssm->ch, ssm->smd_buffer, packet_len);
- if (rc < packet_len) {
+ count = smd_write(ssm->ch, ssm->smd_buffer, packet_len);
+ if (count < packet_len) {
dev_err(ssm->dev, "smd_write failed for %d\n", ipc_req);
rc = -EIO;
}
+out:
return rc;
}
@@ -120,144 +120,44 @@
* Header Format
* Each member of header is of 10 byte (ASCII).
* Each entry is separated by '|' delimiter.
- * |<-10 bytes->|<-10 bytes->|<-10 bytes->|<-10 bytes->|<-10 bytes->|
- * |-----------------------------------------------------------------
- * | length | replay no. | request | msg_len | message |
- * |-----------------------------------------------------------------
+ * |<-10 bytes->|<-10 bytes->|
+ * |-------------------------|
+ * | IPC code | error code |
+ * |-------------------------|
*
*/
-static int decode_header(char *buffer, int length,
- struct ssm_common_msg *pkt)
+static int decode_packet(char *buffer, struct ssm_common_msg *pkt)
{
int rc;
- rc = getint(buffer, &pkt->pktlen);
- if (rc < 0)
- return -EINVAL;
-
- buffer += SSM_MSG_FIELD_LEN;
- rc = getint(buffer, &pkt->replaynum);
- if (rc < 0)
- return -EINVAL;
-
- buffer += SSM_MSG_FIELD_LEN;
rc = getint(buffer, (unsigned long *)&pkt->ipc_req);
if (rc < 0)
return -EINVAL;
buffer += SSM_MSG_FIELD_LEN;
- rc = getint(buffer, &pkt->msg_len);
- if ((rc < 0) || (pkt->msg_len > SSM_MSG_LEN))
+ rc = getint(buffer, (unsigned long *)&pkt->err_code);
+ if (rc < 0)
return -EINVAL;
- pkt->msg = buffer + SSM_MSG_FIELD_LEN;
-
- dev_dbg(ssm_drv->dev, "len %lu rep %lu req %d msg_len %lu\n",
- pkt->pktlen, pkt->replaynum, pkt->ipc_req,
- pkt->msg_len);
+ dev_dbg(ssm_drv->dev, "req %d error code %d\n",
+ pkt->ipc_req, pkt->err_code);
return 0;
}
-/*
- * Decode address for storing the decryption key.
- * Only for Key Exchange
- * Message Format
- * |Length@Address|
- */
-static int decode_message(char *msg, unsigned int len, unsigned long *length,
- unsigned long *address)
+static void process_message(struct ssm_common_msg pkt, struct ssm_driver *ssm)
{
- int i = 0, rc = 0;
- char *buff;
- buff = kzalloc(len, GFP_KERNEL);
- if (!buff)
- return -ENOMEM;
- while (i < len) {
- if (msg[i] == '@')
- break;
- i++;
- }
- if ((i < len) && (msg[i] == '@')) {
- memcpy(buff, msg, i);
- buff[i] = '\0';
- rc = kstrtoul(skip_spaces(buff), 10, length);
- if (rc || (length <= 0)) {
- rc = -EINVAL;
- goto exit;
- }
- memcpy(buff, &msg[i + 1], len - (i + 1));
- buff[len - i] = '\0';
- rc = kstrtoul(skip_spaces(buff), 10, address);
- } else
- rc = -EINVAL;
-
-exit:
- kfree(buff);
- return rc;
-}
-
-static void process_message(int cmd, char *msg, int len,
- struct ssm_driver *ssm)
-{
- int rc;
- unsigned long key_len = 0, key_add = 0, val;
- struct ssm_keyexchg_req req;
-
- switch (cmd) {
- case SSM_MTOA_KEY_EXCHANGE:
- if (len < 3) {
- dev_err(ssm->dev, "Invalid message\n");
- break;
- }
-
- if (ssm->key_status) {
- dev_err(ssm->dev, "Key exchange already done\n");
- break;
- }
-
- rc = decode_message(msg, len, &key_len, &key_add);
- if (rc) {
- rc = update_modem(SSM_ATOM_KEY_STATUS, ssm,
- 1, "1");
- break;
- }
-
- /*
- * We are doing key-exchange part here as it is very
- * specific for this case. For all other tz
- * communication we have generic function.
- */
- req.ssid = MPSS_SUBSYS;
- req.address = (void *)key_add;
- req.length = key_len;
- req.status = (uint32_t *)ssm->buff_phys;
-
- *(unsigned int *)ssm->buff_virt = -1;
- rc = scm_call(KEY_EXCHANGE, 0x1, &req,
- sizeof(struct ssm_keyexchg_req), NULL, 0);
- if (rc) {
- dev_err(ssm->dev, "Call for key exchg failed %d", rc);
- rc = update_modem(SSM_ATOM_KEY_STATUS, ssm,
- 1, "1");
- } else {
- /* Success encode packet and update modem */
- rc = update_modem(SSM_ATOM_KEY_STATUS, ssm,
- 1, "0");
- ssm->key_status = true;
- }
- break;
+ switch (pkt.ipc_req) {
case SSM_MTOA_MODE_UPDATE_STATUS:
- msg[len] = '\0';
- rc = kstrtoul(skip_spaces(msg), 10, &val);
- if (val) {
+ if (pkt.err_code) {
dev_err(ssm->dev, "Modem mode update failed\n");
ssm->update_status = FAILED;
} else
ssm->update_status = SUCCESS;
- dev_dbg(ssm->dev, "Modem mode update status %lu\n", val);
+ dev_dbg(ssm->dev, "Modem mode update status %d\n",
+ pkt.err_code);
break;
default:
@@ -279,7 +179,7 @@
mutex_lock(&ssm->mutex);
sz = smd_cur_packet_size(ssm->ch);
- if ((sz <= 0) || (sz > ATOM_MSG_LEN)) {
+ if ((sz < SSM_MSG_FIELD_LEN) || (sz > ATOM_MSG_LEN)) {
dev_dbg(ssm_drv->dev, "Garbled message size\n");
goto unlock;
}
@@ -289,35 +189,18 @@
goto unlock;
}
- if (sz < SSM_HEADER_LEN) {
- dev_err(ssm_drv->dev, "Invalid packet\n");
- goto unlock;
- }
-
if (smd_read(ssm->ch, ssm->smd_buffer, sz) != sz) {
dev_err(ssm_drv->dev, "Incomplete data\n");
goto unlock;
}
- rc = decode_header(ssm->smd_buffer, sz, &pkt);
+ rc = decode_packet(ssm->smd_buffer, &pkt);
if (rc < 0) {
dev_err(ssm_drv->dev, "Corrupted header\n");
goto unlock;
}
- /* Check validity of message */
- if (ssm->mtoa_replay >= (int)pkt.replaynum) {
- dev_err(ssm_drv->dev, "Replay attack...\n");
- goto unlock;
- }
-
- if (pkt.msg[pkt.msg_len] != '|') {
- dev_err(ssm_drv->dev, "Garbled message\n");
- goto unlock;
- }
-
- ssm->mtoa_replay = pkt.replaynum;
- process_message(pkt.ipc_req, pkt.msg, pkt.msg_len, ssm);
+ process_message(pkt, ssm);
unlock:
mutex_unlock(&ssm->mutex);
@@ -335,8 +218,7 @@
switch (event) {
case SMD_EVENT_OPEN:
case SMD_EVENT_CLOSE:
- dev_info(ssm->dev, "Port %s\n",
- (event == SMD_EVENT_OPEN) ? "opened" : "closed");
+ dev_dbg(ssm->dev, "SMD port status changed\n");
break;
case SMD_EVENT_DATA:
if (smd_read_avail(ssm->ch) > 0)
@@ -346,280 +228,22 @@
}
/*
- * Communication interface between ssm driver and TZ.
- */
-static int tz_scm_call(struct ssm_driver *ssm, void *tz_req, int tz_req_len,
- void **tz_resp, int tz_resp_len)
-{
- int rc;
- struct common_req req;
- struct common_resp resp;
-
- memcpy((void *)ssm->buff_virt, tz_req, tz_req_len);
-
- req.cmd_id = CLIENT_SEND_DATA_COMMAND;
- req.app_id = ssm->app_id;
- req.req_ptr = (void *)ssm->buff_phys;
- req.req_len = tz_req_len;
- req.resp_ptr = (void *)(ssm->buff_phys + tz_req_len);
- req.resp_len = tz_resp_len;
-
- rc = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &req,
- sizeof(req), (void *)&resp, sizeof(resp));
- if (rc) {
- dev_err(ssm->dev, "SCM call failed for data command\n");
- return rc;
- }
-
- if (resp.result != RESULT_SUCCESS) {
- dev_err(ssm->dev, "Data command response failure %d\n",
- resp.result);
- return -EINVAL;
- }
-
- *tz_resp = (void *)(ssm->buff_virt + tz_req_len);
-
- return rc;
-}
-
-/*
* Load SSM application in TZ and start application:
- * 1. Check if SSM application is already loaded.
- * 2. Load SSM application firmware.
- * 3. Start SSM application in TZ.
*/
static int ssm_load_app(struct ssm_driver *ssm)
{
- unsigned char name[MAX_APP_NAME_SIZE], *pos;
- int rc, i, fw_count;
- uint32_t buff_len, size = 0, ion_len;
- struct check_app_req app_req;
- struct scm_resp app_resp;
- struct load_app app_img_info;
- const struct firmware **fw, *fw_mdt;
- const struct elf32_hdr *ehdr;
- const struct elf32_phdr *phdr;
- struct ion_handle *ion_handle;
- ion_phys_addr_t buff_phys;
- void *buff_virt;
+ int rc;
- /* Check if TZ app already loaded */
- app_req.cmd_id = APP_LOOKUP_COMMAND;
- memcpy(app_req.app_name, TZAPP_NAME, MAX_APP_NAME_SIZE);
-
- rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &app_req,
- sizeof(struct check_app_req),
- &app_resp, sizeof(app_resp));
- if (rc) {
- dev_err(ssm->dev, "SCM call failed for LOOKUP COMMAND\n");
- return -EINVAL;
- }
-
- if (app_resp.result == RESULT_FAILURE)
- ssm->app_id = 0;
- else
- ssm->app_id = app_resp.data;
-
- if (ssm->app_id) {
- rc = 0;
- dev_info(ssm->dev, "TZAPP already loaded...\n");
- goto out;
- }
-
- /* APP not loaded get the firmware */
- /* Get .mdt first */
- rc = request_firmware(&fw_mdt, FIRMWARE_NAME".mdt", ssm->dev);
- if (rc) {
- dev_err(ssm->dev, "Unable to get mdt file %s\n",
- FIRMWARE_NAME".mdt");
- rc = -EIO;
- goto out;
- }
-
- if (fw_mdt->size < sizeof(*ehdr)) {
- dev_err(ssm->dev, "Not big enough to be an elf header\n");
- rc = -EIO;
- goto release_mdt;
- }
-
- ehdr = (struct elf32_hdr *)fw_mdt->data;
- if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
- dev_err(ssm->dev, "Not an elf header\n");
- rc = -EIO;
- goto release_mdt;
- }
-
- if (ehdr->e_phnum == 0) {
- dev_err(ssm->dev, "No loadable segments\n");
- rc = -EIO;
- goto release_mdt;
- }
-
- phdr = (const struct elf32_phdr *)(fw_mdt->data +
- sizeof(struct elf32_hdr));
-
- fw = kzalloc((sizeof(struct firmware *) * ehdr->e_phnum), GFP_KERNEL);
- if (!fw) {
- rc = -ENOMEM;
- goto release_mdt;
- }
-
- /* Valid .mdt now we need to load other parts .b0* */
- for (fw_count = 0; fw_count < ehdr->e_phnum ; fw_count++) {
- snprintf(name, MAX_APP_NAME_SIZE, FIRMWARE_NAME".b%02d",
- fw_count);
- rc = request_firmware(&fw[fw_count], name, ssm->dev);
- if (rc < 0) {
- rc = -EIO;
- dev_err(ssm->dev, "Unable to get blob file\n");
- goto release_blob;
- }
-
- if (fw[fw_count]->size != phdr->p_filesz) {
- dev_err(ssm->dev, "Blob size %u doesn't match %u\n",
- fw[fw_count]->size, phdr->p_filesz);
- rc = -EIO;
- goto release_blob;
- }
-
- phdr++;
- size += fw[fw_count]->size;
- }
-
- /* Ion allocation for loading tzapp */
- /* ION buffer size 4k aligned */
- ion_len = ALIGN_BUFFER(size);
- ion_handle = ion_alloc(ssm_drv->ssm_ion_client,
- ion_len, SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), 0);
- if (IS_ERR_OR_NULL(ion_handle)) {
- rc = PTR_ERR(ion_handle);
- dev_err(ssm->dev, "Unable to get ion handle\n");
- goto release_blob;
- }
-
- rc = ion_phys(ssm_drv->ssm_ion_client, ion_handle,
- &buff_phys, &buff_len);
+ /* Load the APP */
+ rc = qseecom_start_app(&ssm->qseecom_handle, TZAPP_NAME, SZ_4K);
if (rc < 0) {
- dev_err(ssm->dev, "Unable to get ion physical address\n");
- goto ion_free;
+ dev_err(ssm->dev, "Unable to load SSM app\n");
+ ssm->app_status = FAILED;
+ return -EIO;
}
- if (buff_len < size) {
- rc = -ENOMEM;
- goto ion_free;
- }
-
- buff_virt = ion_map_kernel(ssm_drv->ssm_ion_client,
- ion_handle);
- if (IS_ERR_OR_NULL((void *)buff_virt)) {
- rc = PTR_ERR((void *)buff_virt);
- dev_err(ssm->dev, "Unable to get ion virtual address\n");
- goto ion_free;
- }
-
- /* Copy firmware to ION memory */
- memcpy((unsigned char *)buff_virt, fw_mdt->data, fw_mdt->size);
- pos = (unsigned char *)buff_virt + fw_mdt->size;
- for (i = 0; i < ehdr->e_phnum; i++) {
- memcpy(pos, fw[i]->data, fw[i]->size);
- pos += fw[i]->size;
- }
-
- /* Loading app */
- app_img_info.cmd_id = APP_START_COMMAND;
- app_img_info.mdt_len = fw_mdt->size;
- app_img_info.img_len = size;
- app_img_info.phy_addr = buff_phys;
-
- /* SCM call to load the TZ APP */
- rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &app_img_info,
- sizeof(struct load_app), &app_resp, sizeof(app_resp));
- if (rc) {
- rc = -EIO;
- dev_err(ssm->dev, "SCM call to load APP failed\n");
- goto ion_unmap;
- }
-
- if (app_resp.result == RESULT_FAILURE) {
- rc = -EIO;
- dev_err(ssm->dev, "SCM command to load TzAPP failed\n");
- goto ion_unmap;
- }
-
- ssm->app_id = app_resp.data;
ssm->app_status = SUCCESS;
-
-ion_unmap:
- ion_unmap_kernel(ssm_drv->ssm_ion_client, ion_handle);
-ion_free:
- ion_free(ssm_drv->ssm_ion_client, ion_handle);
-release_blob:
- while (--fw_count >= 0)
- release_firmware(fw[fw_count]);
- kfree(fw);
-release_mdt:
- release_firmware(fw_mdt);
-out:
- return rc;
-}
-
-/*
- * Allocate buffer for transactions.
- */
-static int ssm_setup_ion(struct ssm_driver *ssm)
-{
- int rc = 0;
- unsigned int size;
-
- size = ALIGN_BUFFER(ATOM_MSG_LEN);
-
- /* ION client for communicating with TZ */
- ssm->ssm_ion_client = msm_ion_client_create(UINT_MAX,
- "ssm-kernel");
- if (IS_ERR_OR_NULL(ssm->ssm_ion_client)) {
- rc = PTR_ERR(ssm->ssm_ion_client);
- dev_err(ssm->dev, "Ion client not created\n");
- return rc;
- }
-
- /* Setup a small ION buffer for tz communication */
- ssm->ssm_ion_handle = ion_alloc(ssm->ssm_ion_client,
- size, SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), 0);
- if (IS_ERR_OR_NULL(ssm->ssm_ion_handle)) {
- rc = PTR_ERR(ssm->ssm_ion_handle);
- dev_err(ssm->dev, "Unable to get ion handle\n");
- goto out;
- }
-
- rc = ion_phys(ssm->ssm_ion_client, ssm->ssm_ion_handle,
- &ssm->buff_phys, &ssm->buff_len);
- if (rc < 0) {
- dev_err(ssm->dev,
- "Unable to get ion buffer physical address\n");
- goto ion_free;
- }
-
- if (ssm->buff_len < size) {
- rc = -ENOMEM;
- goto ion_free;
- }
-
- ssm->buff_virt = ion_map_kernel(ssm->ssm_ion_client,
- ssm->ssm_ion_handle);
- if (IS_ERR_OR_NULL((void *)ssm->buff_virt)) {
- rc = PTR_ERR((void *)ssm->buff_virt);
- dev_err(ssm->dev,
- "Unable to get ion buffer virtual address\n");
- goto ion_free;
- }
-
- return rc;
-
-ion_free:
- ion_free(ssm->ssm_ion_client, ssm->ssm_ion_handle);
-out:
- ion_client_destroy(ssm_drv->ssm_ion_client);
- return rc;
+ return 0;
}
static struct ssm_platform_data *populate_ssm_pdata(struct device *dev)
@@ -649,8 +273,6 @@
static int __devinit ssm_probe(struct platform_device *pdev)
{
int rc;
- uint32_t system_call_id;
- char legacy = '\0';
struct ssm_platform_data *pdata;
struct ssm_driver *drv;
@@ -671,10 +293,16 @@
return -ENOMEM;
}
+ /* Allocate response buffer */
+ drv->resp = devm_kzalloc(&pdev->dev,
+ sizeof(struct tzapp_get_mode_info_rsp),
+ GFP_KERNEL);
+ if (!drv->resp) {
+ rc = -ENOMEM;
+ goto exit;
+ }
+
/* Initialize the driver structure */
- drv->atom_replay = -1;
- drv->mtoa_replay = -1;
- drv->app_id = -1;
drv->app_status = RETRY;
drv->ready = false;
drv->update_status = FAILED;
@@ -691,40 +319,6 @@
goto exit;
}
- /* Allocate response buffer */
- drv->resp = devm_kzalloc(&pdev->dev,
- sizeof(struct tzapp_get_mode_info_rsp),
- GFP_KERNEL);
- if (!drv->resp) {
- rc = -ENOMEM;
- goto exit;
- }
-
-
- /* Check for TZ version */
- system_call_id = QSEOS_CHECK_VERSION_CMD;
- rc = scm_call(SCM_SVC_INFO, SSM_INFO_CMD_ID, &system_call_id,
- sizeof(system_call_id), &legacy, sizeof(legacy));
- if (rc) {
- dev_err(&pdev->dev, "Get version failed %d\n", rc);
- rc = -EINVAL;
- goto exit;
- }
-
- /* This driver only support 1.4 TZ and QSEOS */
- if (!legacy) {
- dev_err(&pdev->dev,
- "Driver doesn't support legacy version\n");
- rc = -EINVAL;
- goto exit;
-
- }
-
- /* Setup the ion buffer for transaction */
- rc = ssm_setup_ion(drv);
- if (rc < 0)
- goto exit;
-
drv->dev = &pdev->dev;
ssm_drv = drv;
platform_set_drvdata(pdev, ssm_drv);
@@ -741,10 +335,6 @@
static int __devexit ssm_remove(struct platform_device *pdev)
{
- int rc;
-
- struct scm_shutdown_req req;
- struct scm_resp resp;
if (!ssm_drv)
return 0;
@@ -758,20 +348,11 @@
smd_close(ssm_drv->ch);
flush_work_sync(&ssm_drv->ipc_work);
- /* ION clean up*/
- ion_unmap_kernel(ssm_drv->ssm_ion_client, ssm_drv->ssm_ion_handle);
- ion_free(ssm_drv->ssm_ion_client, ssm_drv->ssm_ion_handle);
- ion_client_destroy(ssm_drv->ssm_ion_client);
-
/* Shutdown tzapp */
- req.app_id = ssm_drv->app_id;
- req.cmd_id = APP_SHUTDOWN_COMMAND;
- rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
- &resp, sizeof(resp));
- if (rc)
- dev_err(&pdev->dev, "TZ_app Unload failed\n");
+ dev_dbg(&pdev->dev, "Shutting down TZapp\n");
+ qseecom_shutdown_app(&ssm_drv->qseecom_handle);
- return rc;
+ return 0;
}
static struct of_device_id ssm_match_table[] = {
@@ -795,17 +376,15 @@
/*
* Interface for external OEM driver.
* This interface supports following functionalities:
- * 1. Get TZAPP ID.
- * 2. Set default mode.
- * 3. Set mode (encrypted mode and it's length is passed as parameter).
- * 4. Set mode from TZ.
- * 5. Get status of mode update.
+ * 1. Set mode (encrypted mode and it's length is passed as parameter).
+ * 2. Set mode from TZ (read encrypted mode from TZ)
+ * 3. Get status of mode update.
*
*/
int ssm_oem_driver_intf(int cmd, char *mode, int len)
{
int rc, req_len, resp_len;
- struct tzapp_get_mode_info_req get_mode_req;
+ struct tzapp_get_mode_info_req *get_mode_req;
struct tzapp_get_mode_info_rsp *get_mode_resp;
/* If ssm_drv is NULL, probe failed */
@@ -819,7 +398,6 @@
rc = ssm_load_app(ssm_drv);
if (rc) {
rc = -ENODEV;
- ssm_drv->app_status = FAILED;
goto unlock;
}
} else if (ssm_drv->app_status == FAILED) {
@@ -851,23 +429,43 @@
case SSM_READY:
break;
- case SSM_GET_APP_ID:
- rc = ssm_drv->app_id;
- break;
-
case SSM_MODE_INFO_READY:
ssm_drv->update_status = RETRY;
/* Fill command structure */
req_len = sizeof(struct tzapp_get_mode_info_req);
resp_len = sizeof(struct tzapp_get_mode_info_rsp);
- get_mode_req.tzapp_ssm_cmd = GET_ENC_MODE;
- rc = tz_scm_call(ssm_drv, (void *)&get_mode_req,
- req_len, (void **)&get_mode_resp, resp_len);
+ setup_cmd_rsp_buffers(ssm_drv->qseecom_handle,
+ (void **)&get_mode_req, &req_len,
+ (void **)&get_mode_resp, &resp_len);
+ get_mode_req->tzapp_ssm_cmd = GET_ENC_MODE;
+
+ rc = qseecom_set_bandwidth(ssm_drv->qseecom_handle, 1);
if (rc) {
ssm_drv->update_status = FAILED;
+ dev_err(ssm_drv->dev, "set bandwidth failed\n");
+ rc = -EIO;
+ break;
+ }
+ rc = qseecom_send_command(ssm_drv->qseecom_handle,
+ (void *)get_mode_req, req_len,
+ (void *)get_mode_resp, resp_len);
+ if (rc || get_mode_resp->status) {
+ ssm_drv->update_status = FAILED;
break;
}
+ rc = qseecom_set_bandwidth(ssm_drv->qseecom_handle, 0);
+ if (rc) {
+ ssm_drv->update_status = FAILED;
+ dev_err(ssm_drv->dev, "clear bandwidth failed\n");
+ rc = -EIO;
+ break;
+ }
+ if (get_mode_resp->enc_mode_len > ENC_MODE_MAX_SIZE) {
+ ssm_drv->update_status = FAILED;
+ rc = -EINVAL;
+ break;
+ }
/* Send mode_info to modem */
rc = update_modem(SSM_ATOM_MODE_UPDATE, ssm_drv,
get_mode_resp->enc_mode_len,
@@ -899,19 +497,6 @@
rc = ssm_drv->update_status;
break;
- case SSM_SET_DEFAULT_MODE:
- /* Modem does not send response for this */
- ssm_drv->update_status = RETRY;
- rc = update_modem(SSM_ATOM_SET_DEFAULT_MODE, ssm_drv,
- 1, "0");
- if (rc)
- ssm_drv->update_status = FAILED;
- else
- /* For default mode we don't get any resp
- * from modem.
- */
- ssm_drv->update_status = SUCCESS;
- break;
default:
rc = -EINVAL;
dev_err(ssm_drv->dev, "Invalid command\n");
diff --git a/drivers/platform/msm/ssm.h b/drivers/platform/msm/ssm.h
index 97add11..dcda1387 100644
--- a/drivers/platform/msm/ssm.h
+++ b/drivers/platform/msm/ssm.h
@@ -14,8 +14,7 @@
#define __SSM_H_
#define MAX_APP_NAME_SIZE 32
-#define MODE_INFO_MAX_SIZE 4
-#define ENC_MODE_MAX_SIZE (100 + MODE_INFO_MAX_SIZE)
+#define ENC_MODE_MAX_SIZE 200
/* tzapp response.*/
enum tz_response {
@@ -30,35 +29,20 @@
KEY_EXCHANGE = 11,
};
-/* Command list for QSEOS.*/
-enum qceos_cmd_id {
- APP_START_COMMAND = 0x01,
- APP_SHUTDOWN_COMMAND,
- APP_LOOKUP_COMMAND,
- CLIENT_SEND_DATA_COMMAND = 0x6,
- QSEOS_CMD_MAX = 0xEFFFFFFF,
-};
-
/* MODEM/SSM command list.*/
enum ssm_ipc_req {
- SSM_MTOA_KEY_EXCHANGE = 0x0000AAAA,
- SSM_ATOM_KEY_STATUS,
+ SSM_IPC_MIN = 0x0000AAAB,
SSM_ATOM_MODE_UPDATE,
- SSM_MTOA_MODE_UPDATE_STATUS,
- SSM_MTOA_PREV_INVALID,
- SSM_ATOM_PREV_INVALID,
- SSM_ATOM_SET_DEFAULT_MODE,
+ SSM_MTOA_MODE_UPDATE_STATUS = SSM_IPC_MIN + 4,
SSM_INVALID_REQ,
};
/* OEM reuest commands list.*/
enum oem_req {
SSM_READY,
- SSM_GET_APP_ID,
SSM_MODE_INFO_READY,
SSM_SET_MODE,
SSM_GET_MODE_STATUS,
- SSM_SET_DEFAULT_MODE,
SSM_INVALID,
};
@@ -69,33 +53,6 @@
FAILED = -1,
};
-__packed struct load_app {
- uint32_t cmd_id;
- uint32_t mdt_len;
- uint32_t img_len;
- uint32_t phy_addr;
- char app_name[MAX_APP_NAME_SIZE];
-};
-
-/* Stop tzapp reuest.*/
-__packed struct scm_shutdown_req {
- uint32_t cmd_id;
- uint32_t app_id;
-};
-
-/* Common tzos response.*/
-__packed struct scm_resp {
- uint32_t result;
- enum tz_response resp_type;
- unsigned int data;
-};
-
-/* tzos request.*/
-__packed struct check_app_req {
- uint32_t cmd_id;
- char app_name[MAX_APP_NAME_SIZE];
-};
-
/* tzapp encode mode reuest.*/
__packed struct tzapp_mode_enc_req {
uint32_t tzapp_ssm_cmd;
@@ -123,38 +80,11 @@
long status;
};
-/* tzos key exchange request.*/
-__packed struct ssm_keyexchg_req {
- uint32_t ssid;
- void *address;
- uint32_t length;
- uint32_t *status;
-};
-
-/* tzos common request.*/
-__packed struct common_req {
- uint32_t cmd_id;
- uint32_t app_id;
- void *req_ptr;
- uint32_t req_len;
- void *resp_ptr;
- uint32_t resp_len;
-};
-
-/* tzos common response.*/
-__packed struct common_resp {
- uint32_t result;
- uint32_t type;
- uint32_t data;
-};
-
/* Modem/SSM packet format.*/
struct ssm_common_msg {
- unsigned long pktlen;
- unsigned long replaynum;
enum ssm_ipc_req ipc_req;
- unsigned long msg_len;
- char *msg;
+ int err_code;
+
};
#endif
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index b518f1f..c246036 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -1970,6 +1970,11 @@
pr_debug("new delta ocv = %d\n", delta_ocv_uv);
}
+ if (wake_lock_active(&chip->low_voltage_wake_lock)) {
+ pr_debug("Low Voltage, apply only ibat limited corrections\n");
+ goto skip_limiting_corrections;
+ }
+
if (chip->last_ocv_uv > 3800000)
correction_limit_uv = the_chip->high_ocv_correction_limit_uv;
else
@@ -1986,6 +1991,7 @@
pr_debug("new delta ocv = %d\n", delta_ocv_uv);
}
+skip_limiting_corrections:
chip->last_ocv_uv -= delta_ocv_uv;
if (chip->last_ocv_uv >= chip->max_voltage_uv)
@@ -2278,7 +2284,6 @@
int new_calculated_soc;
static int firsttime = 1;
- calib_hkadc_check(chip, batt_temp);
calculate_soc_params(chip, raw, batt_temp, chargecycles,
&fcc_uah,
&unusable_charge_uah,
@@ -2426,6 +2431,7 @@
get_batt_temp(chip, &batt_temp);
mutex_lock(&chip->last_ocv_uv_mutex);
+ calib_hkadc_check(chip, batt_temp);
read_soc_params_raw(chip, &raw, batt_temp);
soc = calculate_state_of_charge(chip, &raw,
@@ -2762,6 +2768,7 @@
get_batt_temp(the_chip, &batt_temp);
mutex_lock(&the_chip->last_ocv_uv_mutex);
+ calib_hkadc_check(the_chip, batt_temp);
read_soc_params_raw(the_chip, &raw, batt_temp);
mutex_unlock(&the_chip->last_ocv_uv_mutex);
@@ -2907,6 +2914,7 @@
mutex_lock(&the_chip->last_ocv_uv_mutex);
+ calib_hkadc_check(the_chip, batt_temp);
read_soc_params_raw(the_chip, &raw, batt_temp);
calculate_cc_uah(the_chip, raw.cc, &bms_end_cc_uah);
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index d5b2cc6..f3f59e6 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -298,6 +298,7 @@
bool disable_aicl;
int usb_type;
bool disable_chg_rmvl_wrkarnd;
+ struct msm_xo_voter *voter;
};
/* user space parameter to limit usb current */
@@ -4034,6 +4035,7 @@
int err;
u8 temp;
+ msm_xo_mode_vote(chip->voter, MSM_XO_MODE_ON);
temp = 0xD1;
err = pm_chg_write(chip, CHG_TEST, temp);
if (err) {
@@ -4092,6 +4094,8 @@
pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
return;
}
+
+ msm_xo_mode_vote(chip->voter, MSM_XO_MODE_OFF);
}
static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
@@ -4099,6 +4103,7 @@
int err;
u8 temp;
+ msm_xo_mode_vote(chip->voter, MSM_XO_MODE_ON);
temp = 0xD1;
err = pm_chg_write(chip, CHG_TEST, temp);
if (err) {
@@ -4112,6 +4117,7 @@
pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
return;
}
+ msm_xo_mode_vote(chip->voter, MSM_XO_MODE_OFF);
}
#define VREF_BATT_THERM_FORCE_ON BIT(7)
@@ -4800,6 +4806,7 @@
chip->ibatmax_max_adj_ma = find_ibat_max_adj_ma(
chip->max_bat_chg_current);
+ chip->voter = msm_xo_get(MSM_XO_TCXO_D0, "pm8921_charger");
rc = pm8921_chg_hw_init(chip);
if (rc) {
pr_err("couldn't init hardware rc=%d\n", rc);
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index cf20a81..73c7e62 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -275,6 +275,9 @@
bool battery_removed;
struct bms_irq sw_cc_thr_irq;
struct bms_irq ocv_thr_irq;
+ struct qpnp_vadc_chip *vadc_dev;
+ struct qpnp_iadc_chip *iadc_dev;
+ struct qpnp_adc_tm_chip *adc_tm_dev;
};
static struct of_device_id qpnp_bms_match_table[] = {
@@ -480,7 +483,7 @@
pr_debug("%u raw converted into %lld uv\n", reading, uv);
uv = adjust_vbatt_reading(chip, uv);
pr_debug("adjusted into %lld uv\n", uv);
- rc = qpnp_vbat_sns_comp_result(&uv);
+ rc = qpnp_vbat_sns_comp_result(chip->vadc_dev, &uv);
if (rc)
pr_debug("could not compensate vbatt\n");
pr_debug("compensated into %lld uv\n", uv);
@@ -514,13 +517,13 @@
return result_uv;
}
-static s64 cc_reverse_adjust_for_gain(s64 uv)
+static s64 cc_reverse_adjust_for_gain(struct qpnp_bms_chip *chip, s64 uv)
{
struct qpnp_iadc_calib calibration;
int gain;
s64 result_uv;
- qpnp_iadc_get_gain_and_offset(&calibration);
+ qpnp_iadc_get_gain_and_offset(chip->iadc_dev, &calibration);
gain = (int)calibration.gain_raw - (int)calibration.offset_raw;
pr_debug("reverse adjusting_uv = %lld\n", uv);
@@ -543,7 +546,7 @@
{
struct qpnp_iadc_calib calibration;
- qpnp_iadc_get_gain_and_offset(&calibration);
+ qpnp_iadc_get_gain_and_offset(chip->iadc_dev, &calibration);
return cc_adjust_for_gain(cc_reading_to_uv(reading),
calibration.gain_raw - calibration.offset_raw);
}
@@ -586,7 +589,7 @@
temp_current = div_s64((vsense_uv * 1000000LL),
(int)chip->r_sense_uohm);
- rc = qpnp_iadc_comp_result(&temp_current);
+ rc = qpnp_iadc_comp_result(chip->iadc_dev, &temp_current);
if (rc)
pr_debug("error compensation failed: %d\n", rc);
@@ -595,12 +598,12 @@
return 0;
}
-static int get_battery_voltage(int *result_uv)
+static int get_battery_voltage(struct qpnp_bms_chip *chip, int *result_uv)
{
int rc;
struct qpnp_vadc_result adc_result;
- rc = qpnp_vadc_read(VBAT_SNS, &adc_result);
+ rc = qpnp_vadc_read(chip->vadc_dev, VBAT_SNS, &adc_result);
if (rc) {
pr_err("error reading adc channel = %d, rc = %d\n",
VBAT_SNS, rc);
@@ -654,14 +657,14 @@
int rc, raw_0625, raw_1250;
struct qpnp_vadc_result result;
- rc = qpnp_vadc_read(REF_625MV, &result);
+ rc = qpnp_vadc_read(chip->vadc_dev, REF_625MV, &result);
if (rc) {
pr_debug("vadc read failed with rc = %d\n", rc);
return rc;
}
raw_0625 = result.adc_code;
- rc = qpnp_vadc_read(REF_125V, &result);
+ rc = qpnp_vadc_read(chip->vadc_dev, REF_125V, &result);
if (rc) {
pr_debug("vadc read failed with rc = %d\n", rc);
return rc;
@@ -806,14 +809,15 @@
pr_err("bms current read failed with rc: %d\n", rc);
return rc;
}
- rc = qpnp_vadc_read(VBAT_SNS, &v_result);
+ rc = qpnp_vadc_read(chip->vadc_dev, VBAT_SNS, &v_result);
if (rc) {
pr_err("vadc read failed with rc: %d\n", rc);
return rc;
}
*vbat_uv = (int)v_result.physical;
} else {
- rc = qpnp_iadc_vadc_sync_read(iadc_channel, &i_result,
+ rc = qpnp_iadc_vadc_sync_read(chip->iadc_dev,
+ iadc_channel, &i_result,
VBAT_SNS, &v_result);
if (rc) {
pr_err("adc sync read failed with rc: %d\n", rc);
@@ -1048,13 +1052,13 @@
software_counter = cc_type == SHDW_CC ?
&chip->software_shdw_cc_uah : &chip->software_cc_uah;
- rc = qpnp_vadc_read(DIE_TEMP, &result);
+ rc = qpnp_vadc_read(chip->vadc_dev, DIE_TEMP, &result);
if (rc) {
pr_err("could not read pmic die temperature: %d\n", rc);
return *software_counter;
}
- qpnp_iadc_get_gain_and_offset(&calibration);
+ qpnp_iadc_get_gain_and_offset(chip->iadc_dev, &calibration);
pr_debug("%scc = %lld, die_temp = %lld\n",
cc_type == SHDW_CC ? "shdw_" : "",
cc, result.physical);
@@ -1064,7 +1068,7 @@
- calibration.offset_raw);
cc_pvh = cc_uv_to_pvh(cc_voltage_uv);
cc_uah = div_s64(cc_pvh, chip->r_sense_uohm);
- rc = qpnp_iadc_comp_result(&cc_uah);
+ rc = qpnp_iadc_comp_result(chip->iadc_dev, &cc_uah);
if (rc)
pr_debug("error compensation failed: %d\n", rc);
if (clear_cc == RESET) {
@@ -1429,7 +1433,7 @@
int rc;
struct qpnp_vadc_result result;
- rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
+ rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX1_BATT_THERM, &result);
if (rc) {
pr_err("Unable to read battery temperature\n");
return rc;
@@ -1689,7 +1693,7 @@
int rc;
bool charging, charging_since_last_report;
- rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
+ rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX1_BATT_THERM, &result);
if (rc) {
pr_err("error reading adc channel = %d, rc = %d\n",
@@ -2060,7 +2064,7 @@
{
int rc, vbat_uv;
- rc = get_battery_voltage(&vbat_uv);
+ rc = get_battery_voltage(chip, &vbat_uv);
if (rc < 0) {
pr_err("adc vbat failed err = %d\n", rc);
return soc;
@@ -2131,9 +2135,9 @@
target_cc_uah = CC_STEP_INCREMENT_UAH;
}
iadc_comp_factor = 100000;
- qpnp_iadc_comp_result(&iadc_comp_factor);
+ qpnp_iadc_comp_result(chip->iadc_dev, &iadc_comp_factor);
target_cc_uah = div64_s64(target_cc_uah * 100000, iadc_comp_factor);
- target_cc_uah = cc_reverse_adjust_for_gain(target_cc_uah);
+ target_cc_uah = cc_reverse_adjust_for_gain(chip, target_cc_uah);
cc_raw_64 = convert_cc_uah_to_raw(chip, target_cc_uah);
cc_raw = convert_s64_to_s36(cc_raw_64);
@@ -2319,7 +2323,7 @@
int voltage_range_uv, voltage_remaining_uv, voltage_based_soc;
int rc, vbat_uv;
- rc = get_battery_voltage(&vbat_uv);
+ rc = get_battery_voltage(chip, &vbat_uv);
if (rc < 0) {
pr_err("adc vbat failed err = %d\n", rc);
return rc;
@@ -2352,14 +2356,16 @@
mutex_lock(&chip->vbat_monitor_mutex);
if (chip->vbat_monitor_params.state_request !=
ADC_TM_HIGH_LOW_THR_DISABLE)
- qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
+ qpnp_adc_tm_channel_measure(chip->adc_tm_dev,
+ &chip->vbat_monitor_params);
mutex_unlock(&chip->vbat_monitor_mutex);
if (chip->use_voltage_soc) {
soc = calculate_soc_from_voltage(chip);
} else {
if (!chip->batfet_closed)
- qpnp_iadc_calibrate_for_trim(true);
- rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
+ qpnp_iadc_calibrate_for_trim(chip->iadc_dev, true);
+ rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX1_BATT_THERM,
+ &result);
if (rc) {
pr_err("error reading vadc LR_MUX1_BATT_THERM = %d, rc = %d\n",
LR_MUX1_BATT_THERM, rc);
@@ -2453,7 +2459,8 @@
chip->vbat_monitor_params.low_thr,
chip->vbat_monitor_params.high_thr);
}
- qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
+ qpnp_adc_tm_channel_measure(chip->adc_tm_dev,
+ &chip->vbat_monitor_params);
mutex_unlock(&chip->vbat_monitor_mutex);
}
@@ -2501,7 +2508,8 @@
chip->vbat_monitor_params.low_thr,
chip->vbat_monitor_params.high_thr);
}
- qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
+ qpnp_adc_tm_channel_measure(chip->adc_tm_dev,
+ &chip->vbat_monitor_params);
mutex_unlock(&chip->vbat_monitor_mutex);
}
@@ -2512,10 +2520,10 @@
struct qpnp_vadc_result result;
int rc;
- rc = qpnp_vadc_read(VBAT_SNS, &result);
+ rc = qpnp_vadc_read(chip->vadc_dev, VBAT_SNS, &result);
pr_debug("vbat = %lld, raw = 0x%x\n", result.physical, result.adc_code);
- get_battery_voltage(&vbat_uv);
+ get_battery_voltage(chip, &vbat_uv);
pr_debug("vbat is at %d, state is at %d\n", vbat_uv, state);
if (state == ADC_TM_LOW_STATE) {
@@ -2525,7 +2533,7 @@
configure_vbat_monitor_low(chip);
} else {
pr_debug("faulty btm trigger, discarding\n");
- qpnp_adc_tm_channel_measure(
+ qpnp_adc_tm_channel_measure(chip->adc_tm_dev,
&chip->vbat_monitor_params);
}
} else if (state == ADC_TM_HIGH_STATE) {
@@ -2535,7 +2543,7 @@
configure_vbat_monitor_high(chip);
} else {
pr_debug("faulty btm trigger, discarding\n");
- qpnp_adc_tm_channel_measure(
+ qpnp_adc_tm_channel_measure(chip->adc_tm_dev,
&chip->vbat_monitor_params);
}
} else {
@@ -2551,7 +2559,8 @@
chip->vbat_monitor_params.state_request = ADC_TM_HIGH_LOW_THR_DISABLE;
- rc = qpnp_adc_tm_disable_chan_meas(&chip->vbat_monitor_params);
+ rc = qpnp_adc_tm_channel_measure(chip->adc_tm_dev,
+ &chip->vbat_monitor_params);
if (rc) {
pr_err("tm disable failed: %d\n", rc);
return rc;
@@ -2571,12 +2580,6 @@
{
int rc;
- rc = qpnp_adc_tm_is_ready();
- if (rc) {
- pr_info("adc tm is not ready yet: %d, defer probe\n", rc);
- return -EPROBE_DEFER;
- }
-
chip->vbat_monitor_params.low_thr = chip->low_voltage_threshold;
chip->vbat_monitor_params.high_thr = chip->max_voltage_uv
- VBATT_ERROR_MARGIN;
@@ -2594,12 +2597,14 @@
chip->vbat_monitor_params.state_request =
ADC_TM_HIGH_LOW_THR_DISABLE;
} else {
- rc = qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
+ rc = qpnp_adc_tm_channel_measure(chip->adc_tm_dev,
+ &chip->vbat_monitor_params);
if (rc) {
pr_err("tm setup failed: %d\n", rc);
- return rc;
+ return rc;
}
}
+
pr_debug("setup complete\n");
return 0;
}
@@ -2893,7 +2898,7 @@
struct qpnp_vadc_result result;
int fcc_uah, new_fcc_uah, delta_cc_uah, delta_soc;
- rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
+ rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX1_BATT_THERM, &result);
if (rc) {
pr_err("Unable to read batt_temp\n");
return;
@@ -2959,7 +2964,7 @@
*/
for (i = 0; (!chip->batfet_closed) && i < MAX_CAL_TRIES; i++) {
- rc = qpnp_iadc_calibrate_for_trim(false);
+ rc = qpnp_iadc_calibrate_for_trim(chip->iadc_dev, false);
/*
* Wait 20mS after calibration and before reading battery
* current. The BMS h/w uses calibration values in the
@@ -3084,11 +3089,11 @@
if (batfet_closed == false) {
/* batfet opened */
schedule_work(&chip->batfet_open_work);
- qpnp_iadc_skip_calibration();
+ qpnp_iadc_skip_calibration(chip->iadc_dev);
} else {
/* batfet closed */
- qpnp_iadc_calibrate_for_trim(true);
- qpnp_iadc_resume_calibration();
+ qpnp_iadc_calibrate_for_trim(chip->iadc_dev, true);
+ qpnp_iadc_resume_calibration(chip->iadc_dev);
}
}
}
@@ -3292,7 +3297,7 @@
int rc;
struct qpnp_vadc_result result;
- rc = qpnp_vadc_read(LR_MUX2_BAT_ID, &result);
+ rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX2_BAT_ID, &result);
if (rc) {
pr_err("error reading batt id channel = %d, rc = %d\n",
LR_MUX2_BAT_ID, rc);
@@ -3383,6 +3388,38 @@
return 0;
}
+static int bms_get_adc(struct qpnp_bms_chip *chip,
+ struct spmi_device *spmi)
+{
+ int rc = 0;
+
+ chip->vadc_dev = qpnp_get_vadc(&spmi->dev, "bms");
+ if (IS_ERR(chip->vadc_dev)) {
+ rc = PTR_ERR(chip->vadc_dev);
+ if (rc != -EPROBE_DEFER)
+ pr_err("vadc property missing, rc=%d\n", rc);
+ return rc;
+ }
+
+ chip->iadc_dev = qpnp_get_iadc(&spmi->dev, "bms");
+ if (IS_ERR(chip->iadc_dev)) {
+ rc = PTR_ERR(chip->iadc_dev);
+ if (rc != -EPROBE_DEFER)
+ pr_err("iadc property missing, rc=%d\n", rc);
+ return rc;
+ }
+
+ chip->adc_tm_dev = qpnp_get_adc_tm(&spmi->dev, "bms");
+ if (IS_ERR(chip->adc_tm_dev)) {
+ rc = PTR_ERR(chip->adc_tm_dev);
+ if (rc != -EPROBE_DEFER)
+ pr_err("adc-tm not ready, defer probe\n");
+ return rc;
+ }
+
+ return 0;
+}
+
#define SPMI_PROP_READ(chip_prop, qpnp_spmi_property, retval) \
do { \
if (retval) \
@@ -3681,7 +3718,7 @@
chip->software_shdw_cc_uah = 0;
}
- rc = qpnp_iadc_get_rsense(&rds_rsense_nohm);
+ rc = qpnp_iadc_get_rsense(chip->iadc_dev, &rds_rsense_nohm);
if (rc) {
pr_err("Unable to read RDS resistance value from IADC; rc = %d\n",
rc);
@@ -3727,7 +3764,7 @@
struct qpnp_vadc_result result;
int rc;
- rc = qpnp_vadc_read(DIE_TEMP, &result);
+ rc = qpnp_vadc_read(chip->vadc_dev, DIE_TEMP, &result);
pr_debug("low = %lld, high = %lld\n",
result.physical - chip->temperature_margin,
@@ -3738,7 +3775,8 @@
- chip->temperature_margin;
chip->die_temp_monitor_params.state_request =
ADC_TM_HIGH_LOW_THR_ENABLE;
- return qpnp_adc_tm_channel_measure(&chip->die_temp_monitor_params);
+ return qpnp_adc_tm_channel_measure(chip->adc_tm_dev,
+ &chip->die_temp_monitor_params);
}
static void btm_notify_die_temp(enum qpnp_tm_state state, void *ctx)
@@ -3747,7 +3785,7 @@
struct qpnp_vadc_result result;
int rc;
- rc = qpnp_vadc_read(DIE_TEMP, &result);
+ rc = qpnp_vadc_read(chip->vadc_dev, DIE_TEMP, &result);
if (state == ADC_TM_LOW_STATE)
pr_debug("low state triggered\n");
@@ -3761,17 +3799,14 @@
static int setup_die_temp_monitoring(struct qpnp_bms_chip *chip)
{
- int rc = qpnp_adc_tm_is_ready();
- if (rc) {
- pr_info("adc tm is not ready yet: %d, defer probe\n", rc);
- return -EPROBE_DEFER;
- }
+ int rc;
+
chip->die_temp_monitor_params.channel = DIE_TEMP;
chip->die_temp_monitor_params.btm_ctx = (void *)chip;
chip->die_temp_monitor_params.timer_interval = ADC_MEAS1_INTERVAL_1S;
chip->die_temp_monitor_params.threshold_notification =
&btm_notify_die_temp;
- refresh_die_temp_monitor(chip);
+ rc = refresh_die_temp_monitor(chip);
if (rc) {
pr_err("tm setup failed: %d\n", rc);
return rc;
@@ -3793,19 +3828,9 @@
return -ENOMEM;
}
- rc = qpnp_vadc_is_ready();
- if (rc) {
- pr_info("vadc not ready: %d, deferring probe\n", rc);
- rc = -EPROBE_DEFER;
+ rc = bms_get_adc(chip, spmi);
+ if (rc < 0)
goto error_read;
- }
-
- rc = qpnp_iadc_is_ready();
- if (rc) {
- pr_info("iadc not ready: %d, deferring probe\n", rc);
- rc = -EPROBE_DEFER;
- goto error_read;
- }
mutex_init(&chip->bms_output_lock);
mutex_init(&chip->last_ocv_uv_mutex);
@@ -3957,7 +3982,7 @@
chip->bms_psy_registered = true;
vbatt = 0;
- rc = get_battery_voltage(&vbatt);
+ rc = get_battery_voltage(chip, &vbatt);
if (rc) {
pr_err("error reading vbat_sns adc channel = %d, rc = %d\n",
VBAT_SNS, rc);
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 950b88a..7f77b75 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -100,6 +100,9 @@
#define BOOST_ENABLE_CONTROL 0x46
#define COMP_OVR1 0xEA
#define BAT_IF_BTC_CTRL 0x49
+#define USB_OCP_THR 0x52
+#define USB_OCP_CLR 0x53
+#define BAT_IF_TEMP_STATUS 0x09
#define REG_OFFSET_PERP_SUBTYPE 0x05
@@ -142,6 +145,11 @@
#define BAT_THM_EN BIT(1)
#define BAT_ID_EN BIT(0)
#define BOOST_PWR_EN BIT(7)
+#define OCP_CLR_BIT BIT(7)
+#define OCP_THR_MASK 0x03
+#define OCP_THR_900_MA 0x02
+#define OCP_THR_500_MA 0x01
+#define OCP_THR_200_MA 0x00
/* Interrupt definitions */
/* smbb_chg_interrupts */
@@ -267,6 +275,7 @@
u16 misc_base;
u16 freq_base;
struct qpnp_chg_irq usbin_valid;
+ struct qpnp_chg_irq usb_ocp;
struct qpnp_chg_irq dcin_valid;
struct qpnp_chg_irq chg_gone;
struct qpnp_chg_irq chg_fastchg;
@@ -327,6 +336,8 @@
struct wake_lock eoc_wake_lock;
struct qpnp_chg_regulator otg_vreg;
struct qpnp_chg_regulator boost_vreg;
+ struct qpnp_vadc_chip *vadc_dev;
+ struct qpnp_adc_tm_chip *adc_tm_dev;
};
@@ -917,7 +928,7 @@
struct qpnp_chg_chip *chip = container_of(work,
struct qpnp_chg_chip, adc_measure_work);
- if (qpnp_adc_tm_channel_measure(&chip->adc_param))
+ if (qpnp_adc_tm_channel_measure(chip->adc_tm_dev, &chip->adc_param))
pr_err("request ADC error\n");
}
@@ -981,6 +992,32 @@
return IRQ_HANDLED;
}
+static irqreturn_t
+qpnp_chg_usb_usb_ocp_irq_handler(int irq, void *_chip)
+{
+ struct qpnp_chg_chip *chip = _chip;
+ int rc;
+
+ pr_debug("usb-ocp triggered\n");
+
+ rc = qpnp_chg_masked_write(chip,
+ chip->usb_chgpth_base + USB_OCP_CLR,
+ OCP_CLR_BIT,
+ OCP_CLR_BIT, 1);
+ if (rc)
+ pr_err("Failed to clear OCP bit rc = %d\n", rc);
+
+ /* force usb ovp fet off */
+ rc = qpnp_chg_masked_write(chip,
+ chip->usb_chgpth_base + CHGR_USB_USB_OTG_CTL,
+ USB_OTG_EN_BIT,
+ USB_OTG_EN_BIT, 1);
+ if (rc)
+ pr_err("Failed to turn off usb ovp rc = %d\n", rc);
+
+ return IRQ_HANDLED;
+}
+
#define ENUM_T_STOP_BIT BIT(0)
static irqreturn_t
qpnp_chg_usb_usbin_valid_irq_handler(int irq, void *_chip)
@@ -1330,7 +1367,7 @@
pr_err("vbat reading not supported for 1.0 rc=%d\n", rc);
return 0;
} else {
- rc = qpnp_vadc_read(VBAT_SNS, &results);
+ rc = qpnp_vadc_read(chip->vadc_dev, VBAT_SNS, &results);
if (rc) {
pr_err("Unable to read vbat rc=%d\n", rc);
return 0;
@@ -1406,7 +1443,7 @@
get_prop_batt_status(struct qpnp_chg_chip *chip)
{
int rc;
- u8 chgr_sts;
+ u8 chgr_sts, bat_if_sts;
if ((qpnp_chg_is_usb_chg_plugged_in(chip) ||
qpnp_chg_is_dc_chg_plugged_in(chip)) && chip->chg_done) {
@@ -1419,9 +1456,15 @@
return POWER_SUPPLY_CHARGE_TYPE_NONE;
}
- if (chgr_sts & TRKL_CHG_ON_IRQ)
+ rc = qpnp_chg_read(chip, &bat_if_sts, INT_RT_STS(chip->bat_if_base), 1);
+ if (rc) {
+ pr_err("failed to read bat_if sts %d\n", rc);
+ return POWER_SUPPLY_CHARGE_TYPE_NONE;
+ }
+
+ if (chgr_sts & TRKL_CHG_ON_IRQ && bat_if_sts & BAT_FET_ON_IRQ)
return POWER_SUPPLY_STATUS_CHARGING;
- if (chgr_sts & FAST_CHG_ON_IRQ)
+ if (chgr_sts & FAST_CHG_ON_IRQ && bat_if_sts & BAT_FET_ON_IRQ)
return POWER_SUPPLY_STATUS_CHARGING;
return POWER_SUPPLY_STATUS_DISCHARGING;
@@ -1523,7 +1566,7 @@
if (chip->use_default_batt_values || !get_prop_batt_present(chip))
return DEFAULT_TEMP;
- rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &results);
+ rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX1_BATT_THERM, &results);
if (rc) {
pr_debug("Unable to read batt temperature rc=%d\n", rc);
return 0;
@@ -1733,8 +1776,7 @@
return -EINVAL;
}
- temp = (safe_current - QPNP_CHG_IBATSAFE_MIN_MA)
- / QPNP_CHG_I_STEP_MA;
+ temp = safe_current / QPNP_CHG_I_STEP_MA;
return qpnp_chg_masked_write(chip,
chip->chgr_base + CHGR_IBAT_SAFE,
QPNP_CHG_I_MASK, temp, 1);
@@ -2346,7 +2388,7 @@
qpnp_chg_set_appropriate_vbatdet(chip);
}
- if (qpnp_adc_tm_channel_measure(&chip->adc_param))
+ if (qpnp_adc_tm_channel_measure(chip->adc_tm_dev, &chip->adc_param))
pr_err("request ADC error\n");
power_supply_changed(&chip->batt_psy);
@@ -2631,6 +2673,27 @@
return rc;
}
+ if ((subtype == SMBBP_USB_CHGPTH_SUBTYPE) ||
+ (subtype == SMBCL_USB_CHGPTH_SUBTYPE)) {
+ chip->usb_ocp.irq = spmi_get_irq_byname(spmi,
+ spmi_resource, "usb-ocp");
+ if (chip->usb_ocp.irq < 0) {
+ pr_err("Unable to get usbin irq\n");
+ return rc;
+ }
+ rc = devm_request_irq(chip->dev,
+ chip->usb_ocp.irq,
+ qpnp_chg_usb_usb_ocp_irq_handler,
+ IRQF_TRIGGER_RISING, "usb-ocp", chip);
+ if (rc < 0) {
+ pr_err("Can't request %d usb-ocp: %d\n",
+ chip->usb_ocp.irq, rc);
+ return rc;
+ }
+
+ enable_irq_wake(chip->usb_ocp.irq);
+ }
+
enable_irq_wake(chip->usbin_valid.irq);
enable_irq_wake(chip->chg_gone.irq);
break;
@@ -2671,7 +2734,7 @@
"qcom,battery-data");
if (node) {
memset(&batt_data, 0, sizeof(struct bms_battery_data));
- rc = qpnp_vadc_read(LR_MUX2_BAT_ID, &result);
+ rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX2_BAT_ID, &result);
if (rc) {
pr_err("error reading batt id channel = %d, rc = %d\n",
LR_MUX2_BAT_ID, rc);
@@ -2685,8 +2748,11 @@
return rc;
}
- if (batt_data.max_voltage_uv >= 0)
+ if (batt_data.max_voltage_uv >= 0) {
chip->max_voltage_mv = batt_data.max_voltage_uv / 1000;
+ chip->safe_voltage_mv = chip->max_voltage_mv
+ + MAX_DELTA_VDD_MAX_MV;
+ }
if (batt_data.iterm_ua >= 0)
chip->term_current = batt_data.iterm_ua / 1000;
}
@@ -2882,6 +2948,16 @@
0xFF,
0x80, 1);
+ if ((subtype == SMBBP_USB_CHGPTH_SUBTYPE) ||
+ (subtype == SMBCL_USB_CHGPTH_SUBTYPE)) {
+ rc = qpnp_chg_masked_write(chip,
+ chip->usb_chgpth_base + USB_OCP_THR,
+ OCP_THR_MASK,
+ OCP_THR_900_MA, 1);
+ if (rc)
+ pr_err("Failed to configure OCP rc = %d\n", rc);
+ }
+
break;
case SMBB_DC_CHGPTH_SUBTYPE:
break;
@@ -2999,6 +3075,7 @@
if (rc) {
/* Select BAT_THM as default BPD scheme */
chip->bpd_detection = BPD_TYPE_BAT_THM;
+ rc = 0;
} else {
chip->bpd_detection = get_bpd(bpd);
if (chip->bpd_detection < 0) {
@@ -3009,9 +3086,11 @@
/* Look up JEITA compliance parameters if cool and warm temp provided */
if (chip->cool_bat_decidegc && chip->warm_bat_decidegc) {
- rc = qpnp_adc_tm_is_ready();
- if (rc) {
- pr_err("tm not ready %d\n", rc);
+ chip->adc_tm_dev = qpnp_get_adc_tm(chip->dev, "chg");
+ if (IS_ERR(chip->adc_tm_dev)) {
+ rc = PTR_ERR(chip->adc_tm_dev);
+ if (rc != -EPROBE_DEFER)
+ pr_err("adc-tm not ready, defer probe\n");
return rc;
}
@@ -3131,14 +3210,18 @@
if (subtype == SMBB_BAT_IF_SUBTYPE ||
subtype == SMBBP_BAT_IF_SUBTYPE ||
- subtype == SMBCL_BAT_IF_SUBTYPE){
- rc = qpnp_vadc_is_ready();
- if (rc)
+ subtype == SMBCL_BAT_IF_SUBTYPE) {
+ chip->vadc_dev = qpnp_get_vadc(chip->dev, "chg");
+ if (IS_ERR(chip->vadc_dev)) {
+ rc = PTR_ERR(chip->vadc_dev);
+ if (rc != -EPROBE_DEFER)
+ pr_err("vadc property missing\n");
goto fail_chg_enable;
rc = qpnp_chg_load_battery_data(chip);
if (rc)
goto fail_chg_enable;
+ }
}
}
@@ -3354,7 +3437,8 @@
chip->adc_param.channel = LR_MUX1_BATT_THERM;
if (get_prop_batt_present(chip)) {
- rc = qpnp_adc_tm_channel_measure(&chip->adc_param);
+ rc = qpnp_adc_tm_channel_measure(chip->adc_tm_dev,
+ &chip->adc_param);
if (rc) {
pr_err("request ADC error %d\n", rc);
goto fail_chg_enable;
@@ -3414,7 +3498,8 @@
struct qpnp_chg_chip *chip = dev_get_drvdata(&spmi->dev);
if (chip->cool_bat_decidegc && chip->warm_bat_decidegc
&& chip->batt_present) {
- qpnp_adc_tm_disable_chan_meas(&chip->adc_param);
+ qpnp_adc_tm_disable_chan_meas(chip->adc_tm_dev,
+ &chip->adc_param);
}
cancel_work_sync(&chip->adc_measure_work);
cancel_delayed_work_sync(&chip->eoc_work);
@@ -3462,66 +3547,6 @@
return rc;
}
-static int
-qpnp_chg_ops_set(const char *val, const struct kernel_param *kp)
-{
- return -EINVAL;
-}
-
-#define MAX_LEN_VADC 10
-static int
-qpnp_chg_usb_in_get(char *val, const struct kernel_param *kp)
-{
- int rc;
- struct qpnp_vadc_result results;
-
- rc = qpnp_vadc_is_ready();
- if (rc)
- return rc;
-
- rc = qpnp_vadc_read(USBIN, &results);
- if (rc) {
- pr_err("Unable to read vchg rc=%d\n", rc);
- return 0;
- }
- rc = snprintf(val, MAX_LEN_VADC, "%lld\n", results.physical);
-
- return rc;
-}
-
-static int
-qpnp_chg_vchg_get(char *val, const struct kernel_param *kp)
-{
- int rc;
- struct qpnp_vadc_result results;
-
- rc = qpnp_vadc_is_ready();
- if (rc)
- return rc;
-
- rc = qpnp_vadc_read(VCHG_SNS, &results);
- if (rc) {
- pr_err("Unable to read vchg rc=%d\n", rc);
- return 0;
- }
- rc = snprintf(val, MAX_LEN_VADC, "%lld\n", results.physical);
-
- return rc;
-}
-
-static struct kernel_param_ops usb_in_uv_param_ops = {
- .set = qpnp_chg_ops_set,
- .get = qpnp_chg_usb_in_get,
-};
-
-static struct kernel_param_ops vchg_uv_param_ops = {
- .set = qpnp_chg_ops_set,
- .get = qpnp_chg_vchg_get,
-};
-
-module_param_cb(usb_in_uv, &usb_in_uv_param_ops, NULL, 0644);
-module_param_cb(vchg_uv, &vchg_uv_param_ops, NULL, 0644);
-
static const struct dev_pm_ops qpnp_chg_pm_ops = {
.resume = qpnp_chg_resume,
.suspend = qpnp_chg_suspend,
diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index 9a4ea63..e3998a5 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -34,7 +34,7 @@
config SCSI_UFSHCD
tristate "Universal Flash Storage Controller Driver Core"
- depends on SCSI
+ depends on SCSI && SCSI_DMA
---help---
This selects the support for UFS devices in Linux, say Y and make
sure that you know the name of your UFS host adapter (the card
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 03319ac..5634caf 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -132,12 +132,6 @@
goto out_iounmap;
}
- err = dma_set_coherent_mask(dev, dev->coherent_dma_mask);
- if (err) {
- dev_err(&pdev->dev, "set dma mask failed\n");
- goto out_iounmap;
- }
-
err = ufshcd_init(&pdev->dev, &hba, mmio_base, irq_res->start);
if (err) {
dev_err(&pdev->dev, "Intialization failed\n");
@@ -184,12 +178,12 @@
mem_size = resource_size(mem_res);
release_mem_region(mem_res->start, mem_size);
}
- platform_set_drvdata(pdev, NULL);
return 0;
}
static const struct of_device_id ufs_of_match[] = {
{ .compatible = "jedec,ufs-1.1"},
+ {},
};
static const struct dev_pm_ops ufshcd_dev_pm_ops = {
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 2230f14..df02ff1 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1349,7 +1349,7 @@
goto fatal_eh;
if (hba->errors & UIC_ERROR) {
- reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
+ reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER);
if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
goto fatal_eh;
}
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index c9b2476..25b4b5e 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -2919,15 +2919,6 @@
goto err_probe_reqmem;
}
- if (pdata && pdata->ver_reg_exists) {
- enum msm_spi_qup_version ver =
- msm_spi_get_qup_hw_ver(&pdev->dev, dd);
- if (dd->qup_ver != ver)
- dev_warn(&pdev->dev,
- "%s: HW version different then initially assumed by probe",
- __func__);
- }
-
if (pdata && pdata->rsl_id) {
struct remote_mutex_id rmid;
rmid.r_spinlock_id = pdata->rsl_id;
@@ -2986,6 +2977,16 @@
}
pclk_enabled = 1;
+
+ if (pdata && pdata->ver_reg_exists) {
+ enum msm_spi_qup_version ver =
+ msm_spi_get_qup_hw_ver(&pdev->dev, dd);
+ if (dd->qup_ver != ver)
+ dev_warn(&pdev->dev,
+ "%s: HW version different then initially assumed by probe",
+ __func__);
+ }
+
/* GSBI dose not exists on B-family MSM-chips */
if (dd->qup_ver != SPI_QUP_VERSION_BFAM) {
rc = msm_spi_configure_gsbi(dd, pdev);
diff --git a/drivers/spmi/qpnp-int.c b/drivers/spmi/qpnp-int.c
index eedb1e5..03e9021 100644
--- a/drivers/spmi/qpnp-int.c
+++ b/drivers/spmi/qpnp-int.c
@@ -167,21 +167,20 @@
pr_err_ratelimited("%s: decode failed on hwirq %lu\n",
__func__, d->hwirq);
return rc;
- } else {
- if (irq_d->priv_d == QPNPINT_INVALID_DATA) {
- rc = chip_d->cb->register_priv_data(chip_d->spmi_ctrl,
- &q_spec, &irq_d->priv_d);
- if (rc) {
- pr_err_ratelimited(
- "%s: decode failed on hwirq %lu\n",
- __func__, d->hwirq);
- return rc;
- }
-
- }
- arb_op(chip_d->spmi_ctrl, &q_spec, irq_d->priv_d);
}
+ if (irq_d->priv_d == QPNPINT_INVALID_DATA) {
+ rc = chip_d->cb->register_priv_data(chip_d->spmi_ctrl,
+ &q_spec, &irq_d->priv_d);
+ if (rc) {
+ pr_err_ratelimited(
+ "%s: decode failed on hwirq %lu rc = %d\n",
+ __func__, d->hwirq, rc);
+ return rc;
+ }
+ }
+ arb_op(chip_d->spmi_ctrl, &q_spec, irq_d->priv_d);
+
return 0;
}
@@ -191,6 +190,7 @@
struct q_chip_data *chip_d = irq_d->chip_d;
struct q_perip_data *per_d = irq_d->per_d;
int rc;
+ uint8_t prev_int_en = per_d->int_en;
pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
@@ -201,10 +201,16 @@
return;
}
- qpnpint_arbiter_op(d, irq_d, chip_d->cb->mask);
-
per_d->int_en &= ~irq_d->mask_shift;
+ if (prev_int_en && !(per_d->int_en)) {
+ /*
+ * no interrupt on this peripheral is enabled
+ * ask the arbiter to ignore this peripheral
+ */
+ qpnpint_arbiter_op(d, irq_d, chip_d->cb->mask);
+ }
+
rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_EN_CLR,
(u8 *)&irq_d->mask_shift, 1);
if (rc) {
@@ -221,6 +227,7 @@
struct q_chip_data *chip_d = irq_d->chip_d;
struct q_perip_data *per_d = irq_d->per_d;
int rc;
+ uint8_t prev_int_en = per_d->int_en;
pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
@@ -231,10 +238,16 @@
return;
}
- qpnpint_arbiter_op(d, irq_d, chip_d->cb->mask);
-
per_d->int_en &= ~irq_d->mask_shift;
+ if (prev_int_en && !(per_d->int_en)) {
+ /*
+ * no interrupt on this peripheral is enabled
+ * ask the arbiter to ignore this peripheral
+ */
+ qpnpint_arbiter_op(d, irq_d, chip_d->cb->mask);
+ }
+
rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_EN_CLR,
&irq_d->mask_shift, 1);
if (rc) {
@@ -256,6 +269,7 @@
struct q_chip_data *chip_d = irq_d->chip_d;
struct q_perip_data *per_d = irq_d->per_d;
int rc;
+ uint8_t prev_int_en = per_d->int_en;
pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
@@ -266,9 +280,15 @@
return;
}
- qpnpint_arbiter_op(d, irq_d, chip_d->cb->unmask);
-
per_d->int_en |= irq_d->mask_shift;
+ if (!prev_int_en && per_d->int_en) {
+ /*
+ * no interrupt prior to this call was enabled for the
+ * peripheral. Ask the arbiter to enable interrupts for
+ * this peripheral
+ */
+ qpnpint_arbiter_op(d, irq_d, chip_d->cb->unmask);
+ }
rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_EN_SET,
&irq_d->mask_shift, 1);
if (rc) {
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index 05a4806..f85a576 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -101,6 +101,9 @@
#define PMIC_ARB_APID_MASK 0xFF
#define PMIC_ARB_PPID_MASK 0xFFF
+/* interrupt enable bit */
+#define SPMI_PIC_ACC_ENABLE_BIT BIT(0)
+
/**
* base - base address of the PMIC Arbiter core registers.
* intr - base address of the SPMI interrupt control registers
@@ -434,8 +437,10 @@
spin_lock_irqsave(&pmic_arb->lock, flags);
status = readl_relaxed(pmic_arb->intr + SPMI_PIC_ACC_ENABLE(apid));
- if (!status) {
- writel_relaxed(0x1, pmic_arb->intr + SPMI_PIC_ACC_ENABLE(apid));
+ if (!(status & SPMI_PIC_ACC_ENABLE_BIT)) {
+ status = status | SPMI_PIC_ACC_ENABLE_BIT;
+ writel_relaxed(status,
+ pmic_arb->intr + SPMI_PIC_ACC_ENABLE(apid));
/* Interrupt needs to be enabled before returning to caller */
wmb();
}
@@ -467,8 +472,11 @@
spin_lock_irqsave(&pmic_arb->lock, flags);
status = readl_relaxed(pmic_arb->intr + SPMI_PIC_ACC_ENABLE(apid));
- if (status) {
- writel_relaxed(0x0, pmic_arb->intr + SPMI_PIC_ACC_ENABLE(apid));
+ if (status & SPMI_PIC_ACC_ENABLE_BIT) {
+ /* clear the enable bit and write */
+ status = status & ~SPMI_PIC_ACC_ENABLE_BIT;
+ writel_relaxed(status,
+ pmic_arb->intr + SPMI_PIC_ACC_ENABLE(apid));
/* Interrupt needs to be disabled before returning to caller */
wmb();
}
@@ -480,7 +488,7 @@
periph_interrupt(struct spmi_pmic_arb_dev *pmic_arb, u8 apid)
{
u16 ppid = get_peripheral_id(pmic_arb, apid);
- void __iomem *base = pmic_arb->intr;
+ void __iomem *intr = pmic_arb->intr;
u8 sid = (ppid >> 8) & 0x0F;
u8 pid = ppid & 0xFF;
u32 status;
@@ -491,11 +499,20 @@
/* return IRQ_NONE; */
}
+ status = readl_relaxed(intr + SPMI_PIC_ACC_ENABLE(apid));
+ if (!(status & SPMI_PIC_ACC_ENABLE_BIT)) {
+ /*
+ * All interrupts from this peripheral are disabled
+ * don't bother calling the qpnpint handler
+ */
+ return IRQ_HANDLED;
+ }
+
/* Read the peripheral specific interrupt bits */
- status = readl_relaxed(base + SPMI_PIC_IRQ_STATUS(apid));
+ status = readl_relaxed(intr + SPMI_PIC_IRQ_STATUS(apid));
/* Clear the peripheral interrupts */
- writel_relaxed(status, base + SPMI_PIC_IRQ_CLEAR(apid));
+ writel_relaxed(status, intr + SPMI_PIC_IRQ_CLEAR(apid));
/* Interrupt needs to be cleared/acknowledged before exiting ISR */
mb();
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index fc21fbb..348ed3e 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -363,21 +363,27 @@
static inline int
spmi_cmd(struct spmi_controller *ctrl, u8 opcode, u8 sid)
{
- BUG_ON(!ctrl || !ctrl->cmd);
+ if (!ctrl || !ctrl->cmd || ctrl->dev.type != &spmi_ctrl_type)
+ return -EINVAL;
+
return ctrl->cmd(ctrl, opcode, sid);
}
static inline int spmi_read_cmd(struct spmi_controller *ctrl,
u8 opcode, u8 sid, u16 addr, u8 bc, u8 *buf)
{
- BUG_ON(!ctrl || !ctrl->read_cmd);
+ if (!ctrl || !ctrl->read_cmd || ctrl->dev.type != &spmi_ctrl_type)
+ return -EINVAL;
+
return ctrl->read_cmd(ctrl, opcode, sid, addr, bc, buf);
}
static inline int spmi_write_cmd(struct spmi_controller *ctrl,
u8 opcode, u8 sid, u16 addr, u8 bc, u8 *buf)
{
- BUG_ON(!ctrl || !ctrl->write_cmd);
+ if (!ctrl || !ctrl->write_cmd || ctrl->dev.type != &spmi_ctrl_type)
+ return -EINVAL;
+
return ctrl->write_cmd(ctrl, opcode, sid, addr, bc, buf);
}
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index 3b0ef8c..5b78cdd 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -171,6 +171,7 @@
struct qpnp_adc_tm_sensor {
struct thermal_zone_device *tz_dev;
+ struct qpnp_adc_tm_chip *chip;
enum thermal_device_mode mode;
uint32_t sensor_num;
enum qpnp_adc_meas_timer_select timer_select;
@@ -187,14 +188,18 @@
uint32_t scale_type;
};
-struct qpnp_adc_tm_drv {
+struct qpnp_adc_tm_chip {
struct qpnp_adc_drv *adc;
+ struct list_head list;
bool adc_tm_initialized;
int max_channels_available;
+ struct qpnp_vadc_chip *vadc_dev;
+ struct work_struct trigger_high_thr_work;
+ struct work_struct trigger_low_thr_work;
struct qpnp_adc_tm_sensor sensor[0];
};
-struct qpnp_adc_tm_drv *qpnp_adc_tm;
+LIST_HEAD(qpnp_adc_tm_device_list);
struct qpnp_adc_tm_trip_reg_type {
uint16_t low_thr_lsb_addr;
@@ -257,67 +262,79 @@
[SCALE_RPMIC_THERM] = {qpnp_adc_scale_millidegc_pmic_voltage_thr},
};
-static int32_t qpnp_adc_tm_read_reg(int16_t reg, u8 *data)
+static int32_t qpnp_adc_tm_read_reg(struct qpnp_adc_tm_chip *chip,
+ int16_t reg, u8 *data)
{
- struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
int rc = 0;
- rc = spmi_ext_register_readl(adc_tm->adc->spmi->ctrl,
- adc_tm->adc->slave, (adc_tm->adc->offset + reg), data, 1);
+ rc = spmi_ext_register_readl(chip->adc->spmi->ctrl,
+ chip->adc->slave, (chip->adc->offset + reg), data, 1);
if (rc < 0)
pr_err("adc-tm read reg %d failed with %d\n", reg, rc);
return rc;
}
-static int32_t qpnp_adc_tm_write_reg(int16_t reg, u8 data)
+static int32_t qpnp_adc_tm_write_reg(struct qpnp_adc_tm_chip *chip,
+ int16_t reg, u8 data)
{
- struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
int rc = 0;
u8 *buf;
buf = &data;
- rc = spmi_ext_register_writel(adc_tm->adc->spmi->ctrl,
- adc_tm->adc->slave, (adc_tm->adc->offset + reg), buf, 1);
+ rc = spmi_ext_register_writel(chip->adc->spmi->ctrl,
+ chip->adc->slave, (chip->adc->offset + reg), buf, 1);
if (rc < 0)
pr_err("adc-tm write reg %d failed with %d\n", reg, rc);
return rc;
}
-static int32_t qpnp_adc_tm_enable(void)
+static int32_t qpnp_adc_tm_enable(struct qpnp_adc_tm_chip *chip)
{
int rc = 0;
u8 data = 0;
data = QPNP_ADC_TM_EN;
- rc = qpnp_adc_tm_write_reg(QPNP_EN_CTL1, data);
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_EN_CTL1, data);
if (rc < 0)
pr_err("adc-tm enable failed\n");
return rc;
}
-static int32_t qpnp_adc_tm_disable(void)
+static int32_t qpnp_adc_tm_disable(struct qpnp_adc_tm_chip *chip)
{
u8 data = 0;
int rc = 0;
- rc = qpnp_adc_tm_write_reg(QPNP_EN_CTL1, data);
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_EN_CTL1, data);
if (rc < 0)
pr_err("adc-tm disable failed\n");
return rc;
}
-static int32_t qpnp_adc_tm_enable_if_channel_meas(void)
+static int qpnp_adc_tm_is_valid(struct qpnp_adc_tm_chip *chip)
+{
+ struct qpnp_adc_tm_chip *adc_tm_chip = NULL;
+
+ list_for_each_entry(adc_tm_chip, &qpnp_adc_tm_device_list, list)
+ if (chip == adc_tm_chip)
+ return 0;
+
+ return -EINVAL;
+}
+
+static int32_t qpnp_adc_tm_enable_if_channel_meas(
+ struct qpnp_adc_tm_chip *chip)
{
u8 adc_tm_meas_en = 0;
int rc = 0;
/* Check if a measurement request is still required */
- rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MULTI_MEAS_EN,
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
&adc_tm_meas_en);
if (rc) {
pr_err("adc-tm-tm read status high failed with %d\n", rc);
@@ -326,10 +343,11 @@
/* Enable only if there are pending measurement requests */
if (adc_tm_meas_en) {
- qpnp_adc_tm_enable();
+ qpnp_adc_tm_enable(chip);
/* Request conversion */
- rc = qpnp_adc_tm_write_reg(QPNP_CONV_REQ, QPNP_CONV_REQ_SET);
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_CONV_REQ,
+ QPNP_CONV_REQ_SET);
if (rc < 0) {
pr_err("adc-tm request conversion failed\n");
return rc;
@@ -339,13 +357,13 @@
return rc;
}
-static int32_t qpnp_adc_tm_req_sts_check(void)
+static int32_t qpnp_adc_tm_req_sts_check(struct qpnp_adc_tm_chip *chip)
{
u8 status1;
int rc, count = 0;
/* The VADC_TM bank needs to be disabled for new conversion request */
- rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS1, &status1);
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1);
if (rc) {
pr_err("adc-tm read status1 failed\n");
return rc;
@@ -353,7 +371,7 @@
/* Disable the bank if a conversion is occuring */
while ((status1 & QPNP_STATUS1_REQ_STS) && (count < 5)) {
- rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS1, &status1);
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1);
if (rc < 0)
pr_err("adc-tm disable failed\n");
/* Wait time is based on the optimum sampling rate
@@ -366,18 +384,19 @@
return rc;
}
-static int32_t qpnp_adc_tm_check_revision(uint32_t btm_chan_num)
+static int32_t qpnp_adc_tm_check_revision(struct qpnp_adc_tm_chip *chip,
+ uint32_t btm_chan_num)
{
u8 rev, perph_subtype;
int rc = 0;
- rc = qpnp_adc_tm_read_reg(QPNP_REVISION3, &rev);
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_REVISION3, &rev);
if (rc) {
pr_err("adc-tm revision read failed\n");
return rc;
}
- rc = qpnp_adc_tm_read_reg(QPNP_PERPH_SUBTYPE, &perph_subtype);
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_PERPH_SUBTYPE, &perph_subtype);
if (rc) {
pr_err("adc-tm perph_subtype read failed\n");
return rc;
@@ -393,21 +412,23 @@
return rc;
}
-static int32_t qpnp_adc_tm_mode_select(u8 mode_ctl)
+static int32_t qpnp_adc_tm_mode_select(struct qpnp_adc_tm_chip *chip,
+ u8 mode_ctl)
{
int rc;
mode_ctl |= (QPNP_ADC_TRIM_EN | QPNP_AMUX_TRIM_EN);
/* VADC_BTM current sets mode to recurring measurements */
- rc = qpnp_adc_tm_write_reg(QPNP_MODE_CTL, mode_ctl);
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_MODE_CTL, mode_ctl);
if (rc < 0)
pr_err("adc-tm write mode selection err\n");
return rc;
}
-static int32_t qpnp_adc_tm_timer_interval_select(uint32_t btm_chan,
+static int32_t qpnp_adc_tm_timer_interval_select(
+ struct qpnp_adc_tm_chip *chip, uint32_t btm_chan,
struct qpnp_vadc_chan_properties *chan_prop)
{
int rc;
@@ -416,7 +437,8 @@
/* Configure kernel clients to timer1 */
switch (chan_prop->timer_select) {
case ADC_MEAS_TIMER_SELECT1:
- rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL,
+ rc = qpnp_adc_tm_write_reg(chip,
+ QPNP_ADC_TM_MEAS_INTERVAL_CTL,
chan_prop->meas_interval1);
if (rc < 0) {
pr_err("timer1 configure failed\n");
@@ -425,7 +447,8 @@
break;
case ADC_MEAS_TIMER_SELECT2:
/* Thermal channels uses timer2, default to 1 second */
- rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+ rc = qpnp_adc_tm_read_reg(chip,
+ QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
&meas_interval_timer2);
if (rc < 0) {
pr_err("timer2 configure read failed\n");
@@ -434,7 +457,8 @@
meas_interval_timer2 |=
(chan_prop->meas_interval2 <<
QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT);
- rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+ rc = qpnp_adc_tm_write_reg(chip,
+ QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
meas_interval_timer2);
if (rc < 0) {
pr_err("timer2 configure failed\n");
@@ -442,7 +466,8 @@
}
break;
case ADC_MEAS_TIMER_SELECT3:
- rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+ rc = qpnp_adc_tm_read_reg(chip,
+ QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
&meas_interval_timer2);
if (rc < 0) {
pr_err("timer3 read failed\n");
@@ -450,7 +475,8 @@
}
chan_prop->meas_interval2 = ADC_MEAS3_INTERVAL_1S;
meas_interval_timer2 |= chan_prop->meas_interval2;
- rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+ rc = qpnp_adc_tm_write_reg(chip,
+ QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
meas_interval_timer2);
if (rc < 0) {
pr_err("timer3 configure failed\n");
@@ -468,13 +494,13 @@
return rc;
}
-static int32_t qpnp_adc_tm_reg_update(uint16_t addr,
- u8 mask, bool state)
+static int32_t qpnp_adc_tm_reg_update(struct qpnp_adc_tm_chip *chip,
+ uint16_t addr, u8 mask, bool state)
{
u8 reg_value = 0;
int rc = 0;
- rc = qpnp_adc_tm_read_reg(addr, ®_value);
+ rc = qpnp_adc_tm_read_reg(chip, addr, ®_value);
if (rc < 0) {
pr_err("read failed for addr:0x%x\n", addr);
return rc;
@@ -486,7 +512,7 @@
pr_debug("state:%d, reg:0x%x with bits:0x%x and mask:0x%x\n",
state, addr, reg_value, ~mask);
- rc = qpnp_adc_tm_write_reg(addr, reg_value);
+ rc = qpnp_adc_tm_write_reg(chip, addr, reg_value);
if (rc < 0) {
pr_err("write failed for addr:%x\n", addr);
return rc;
@@ -495,12 +521,13 @@
return rc;
}
-static int32_t qpnp_adc_tm_thr_update(uint32_t btm_chan,
+static int32_t qpnp_adc_tm_thr_update(struct qpnp_adc_tm_chip *chip,
+ uint32_t btm_chan,
struct qpnp_vadc_chan_properties *chan_prop)
{
int rc = 0;
- rc = qpnp_adc_tm_write_reg(
+ rc = qpnp_adc_tm_write_reg(chip,
adc_tm_data[btm_chan].low_thr_lsb_addr,
QPNP_ADC_TM_THR_LSB_MASK(chan_prop->low_thr));
if (rc < 0) {
@@ -508,7 +535,7 @@
return rc;
}
- rc = qpnp_adc_tm_write_reg(
+ rc = qpnp_adc_tm_write_reg(chip,
adc_tm_data[btm_chan].low_thr_msb_addr,
QPNP_ADC_TM_THR_MSB_MASK(chan_prop->low_thr));
if (rc < 0) {
@@ -516,7 +543,7 @@
return rc;
}
- rc = qpnp_adc_tm_write_reg(
+ rc = qpnp_adc_tm_write_reg(chip,
adc_tm_data[btm_chan].high_thr_lsb_addr,
QPNP_ADC_TM_THR_LSB_MASK(chan_prop->high_thr));
if (rc < 0) {
@@ -524,7 +551,7 @@
return rc;
}
- rc = qpnp_adc_tm_write_reg(
+ rc = qpnp_adc_tm_write_reg(chip,
adc_tm_data[btm_chan].high_thr_msb_addr,
QPNP_ADC_TM_THR_MSB_MASK(chan_prop->high_thr));
if (rc < 0)
@@ -536,17 +563,17 @@
return rc;
}
-static int32_t qpnp_adc_tm_channel_configure(uint32_t btm_chan,
+static int32_t qpnp_adc_tm_channel_configure(struct qpnp_adc_tm_chip *chip,
+ uint32_t btm_chan,
struct qpnp_vadc_chan_properties *chan_prop,
uint32_t amux_channel)
{
- struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
int rc = 0, i = 0, chan_idx = 0;
bool chan_found = false;
u8 sensor_mask = 0;
- while (i < adc_tm->max_channels_available) {
- if (adc_tm->sensor[i].btm_channel_num == btm_chan) {
+ while (i < chip->max_channels_available) {
+ if (chip->sensor[i].btm_channel_num == btm_chan) {
chan_idx = i;
chan_found = true;
i++;
@@ -560,9 +587,9 @@
}
sensor_mask = 1 << chan_idx;
- if (!adc_tm->sensor[chan_idx].thermal_node) {
+ if (!chip->sensor[chan_idx].thermal_node) {
/* Update low and high notification thresholds */
- rc = qpnp_adc_tm_thr_update(btm_chan,
+ rc = qpnp_adc_tm_thr_update(chip, btm_chan,
chan_prop);
if (rc < 0) {
pr_err("setting chan:%d threshold failed\n", btm_chan);
@@ -576,7 +603,7 @@
pr_debug("low sensor mask:%x with state:%d\n",
sensor_mask, chan_prop->state_request);
/* Enable low threshold's interrupt */
- rc = qpnp_adc_tm_reg_update(
+ rc = qpnp_adc_tm_reg_update(chip,
QPNP_ADC_TM_LOW_THR_INT_EN, sensor_mask, true);
if (rc < 0) {
pr_err("low thr enable err:%d\n", btm_chan);
@@ -590,7 +617,7 @@
ADC_TM_HIGH_LOW_THR_ENABLE)) {
/* Enable high threshold's interrupt */
pr_debug("high sensor mask:%x\n", sensor_mask);
- rc = qpnp_adc_tm_reg_update(
+ rc = qpnp_adc_tm_reg_update(chip,
QPNP_ADC_TM_HIGH_THR_INT_EN, sensor_mask, true);
if (rc < 0) {
pr_err("high thr enable err:%d\n", btm_chan);
@@ -600,7 +627,7 @@
}
/* Enable corresponding BTM channel measurement */
- rc = qpnp_adc_tm_reg_update(
+ rc = qpnp_adc_tm_reg_update(chip,
QPNP_ADC_TM_MULTI_MEAS_EN, sensor_mask, true);
if (rc < 0) {
pr_err("multi measurement en failed\n");
@@ -610,7 +637,7 @@
return rc;
}
-static int32_t qpnp_adc_tm_configure(
+static int32_t qpnp_adc_tm_configure(struct qpnp_adc_tm_chip *chip,
struct qpnp_adc_amux_properties *chan_prop)
{
u8 decimation = 0, op_cntrl = 0;
@@ -618,19 +645,19 @@
uint32_t btm_chan = 0;
/* Disable bank */
- rc = qpnp_adc_tm_disable();
+ rc = qpnp_adc_tm_disable(chip);
if (rc)
return rc;
/* Check if a conversion is in progress */
- rc = qpnp_adc_tm_req_sts_check();
+ rc = qpnp_adc_tm_req_sts_check(chip);
if (rc < 0) {
pr_err("adc-tm req_sts check failed\n");
return rc;
}
/* Set measurement in recurring mode */
- rc = qpnp_adc_tm_mode_select(chan_prop->mode_sel);
+ rc = qpnp_adc_tm_mode_select(chip, chan_prop->mode_sel);
if (rc < 0) {
pr_err("adc-tm mode select failed\n");
return rc;
@@ -638,7 +665,7 @@
/* Configure AMUX channel select for the corresponding BTM channel*/
btm_chan = chan_prop->chan_prop->tm_channel_select;
- rc = qpnp_adc_tm_write_reg(btm_chan, chan_prop->amux_channel);
+ rc = qpnp_adc_tm_write_reg(chip, btm_chan, chan_prop->amux_channel);
if (rc < 0) {
pr_err("adc-tm channel selection err\n");
return rc;
@@ -647,14 +674,14 @@
/* Digital paramater setup */
decimation |= chan_prop->decimation <<
QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT;
- rc = qpnp_adc_tm_write_reg(QPNP_ADC_DIG_PARAM, decimation);
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_DIG_PARAM, decimation);
if (rc < 0) {
pr_err("adc-tm digital parameter setup err\n");
return rc;
}
/* Hardware setting time */
- rc = qpnp_adc_tm_write_reg(QPNP_HW_SETTLE_DELAY,
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_HW_SETTLE_DELAY,
chan_prop->hw_settle_time);
if (rc < 0) {
pr_err("adc-tm hw settling time setup err\n");
@@ -662,7 +689,7 @@
}
/* Fast averaging setup */
- rc = qpnp_adc_tm_write_reg(QPNP_FAST_AVG_CTL,
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_FAST_AVG_CTL,
chan_prop->fast_avg_setup);
if (rc < 0) {
pr_err("adc-tm fast-avg setup err\n");
@@ -670,7 +697,7 @@
}
/* Measurement interval setup */
- rc = qpnp_adc_tm_timer_interval_select(btm_chan,
+ rc = qpnp_adc_tm_timer_interval_select(chip, btm_chan,
chan_prop->chan_prop);
if (rc < 0) {
pr_err("adc-tm timer select failed\n");
@@ -678,17 +705,18 @@
}
/* Channel configuration setup */
- rc = qpnp_adc_tm_channel_configure(btm_chan, chan_prop->chan_prop,
- chan_prop->amux_channel);
+ rc = qpnp_adc_tm_channel_configure(chip, btm_chan,
+ chan_prop->chan_prop, chan_prop->amux_channel);
if (rc < 0) {
pr_err("adc-tm channel configure failed\n");
return rc;
}
/* Recurring interval measurement enable */
- rc = qpnp_adc_tm_read_reg(QPNP_ADC_MEAS_INTERVAL_OP_CTL, &op_cntrl);
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_MEAS_INTERVAL_OP_CTL,
+ &op_cntrl);
op_cntrl |= QPNP_ADC_MEAS_INTERVAL_OP;
- rc = qpnp_adc_tm_reg_update(QPNP_ADC_MEAS_INTERVAL_OP_CTL,
+ rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_MEAS_INTERVAL_OP_CTL,
op_cntrl, true);
if (rc < 0) {
pr_err("adc-tm meas interval op configure failed\n");
@@ -696,12 +724,12 @@
}
/* Enable bank */
- rc = qpnp_adc_tm_enable();
+ rc = qpnp_adc_tm_enable(chip);
if (rc)
return rc;
/* Request conversion */
- rc = qpnp_adc_tm_write_reg(QPNP_CONV_REQ, QPNP_CONV_REQ_SET);
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_CONV_REQ, QPNP_CONV_REQ_SET);
if (rc < 0) {
pr_err("adc-tm request conversion failed\n");
return rc;
@@ -713,13 +741,13 @@
static int qpnp_adc_tm_get_mode(struct thermal_zone_device *thermal,
enum thermal_device_mode *mode)
{
- struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
+ struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
- if (!adc_tm_sensor || qpnp_adc_tm_check_revision(
- adc_tm_sensor->btm_channel_num) || !mode)
+ if ((IS_ERR(adc_tm)) || qpnp_adc_tm_check_revision(
+ adc_tm->chip, adc_tm->btm_channel_num))
return -EINVAL;
- *mode = adc_tm_sensor->mode;
+ *mode = adc_tm->mode;
return 0;
}
@@ -728,35 +756,38 @@
enum thermal_device_mode mode)
{
struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
- struct qpnp_adc_tm_drv *adc_drv = qpnp_adc_tm;
+ struct qpnp_adc_tm_chip *chip = adc_tm->chip;
int rc = 0, channel;
u8 sensor_mask = 0;
- if (!adc_tm || qpnp_adc_tm_check_revision(adc_tm->btm_channel_num))
+ if (qpnp_adc_tm_is_valid(chip))
+ return -ENODEV;
+
+ if (qpnp_adc_tm_check_revision(chip, adc_tm->btm_channel_num))
return -EINVAL;
if (mode == THERMAL_DEVICE_ENABLED) {
- adc_drv->adc->amux_prop->amux_channel =
+ chip->adc->amux_prop->amux_channel =
adc_tm->vadc_channel_num;
channel = adc_tm->sensor_num;
- adc_drv->adc->amux_prop->decimation =
- adc_drv->adc->adc_channels[channel].adc_decimation;
- adc_drv->adc->amux_prop->hw_settle_time =
- adc_drv->adc->adc_channels[channel].hw_settle_time;
- adc_drv->adc->amux_prop->fast_avg_setup =
- adc_drv->adc->adc_channels[channel].fast_avg_setup;
- adc_drv->adc->amux_prop->mode_sel =
+ chip->adc->amux_prop->decimation =
+ chip->adc->adc_channels[channel].adc_decimation;
+ chip->adc->amux_prop->hw_settle_time =
+ chip->adc->adc_channels[channel].hw_settle_time;
+ chip->adc->amux_prop->fast_avg_setup =
+ chip->adc->adc_channels[channel].fast_avg_setup;
+ chip->adc->amux_prop->mode_sel =
ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
- adc_drv->adc->amux_prop->chan_prop->timer_select =
+ chip->adc->amux_prop->chan_prop->timer_select =
ADC_MEAS_TIMER_SELECT1;
- adc_drv->adc->amux_prop->chan_prop->meas_interval1 =
+ chip->adc->amux_prop->chan_prop->meas_interval1 =
ADC_MEAS1_INTERVAL_1S;
- adc_drv->adc->amux_prop->chan_prop->low_thr = adc_tm->low_thr;
- adc_drv->adc->amux_prop->chan_prop->high_thr = adc_tm->high_thr;
- adc_drv->adc->amux_prop->chan_prop->tm_channel_select =
+ chip->adc->amux_prop->chan_prop->low_thr = adc_tm->low_thr;
+ chip->adc->amux_prop->chan_prop->high_thr = adc_tm->high_thr;
+ chip->adc->amux_prop->chan_prop->tm_channel_select =
adc_tm->btm_channel_num;
- rc = qpnp_adc_tm_configure(adc_drv->adc->amux_prop);
+ rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop);
if (rc) {
pr_err("adc-tm tm configure failed with %d\n", rc);
return -EINVAL;
@@ -764,27 +795,27 @@
} else if (mode == THERMAL_DEVICE_DISABLED) {
sensor_mask = 1 << adc_tm->sensor_num;
/* Disable bank */
- rc = qpnp_adc_tm_disable();
+ rc = qpnp_adc_tm_disable(chip);
if (rc < 0) {
pr_err("adc-tm disable failed\n");
return rc;
}
/* Check if a conversion is in progress */
- rc = qpnp_adc_tm_req_sts_check();
+ rc = qpnp_adc_tm_req_sts_check(chip);
if (rc < 0) {
pr_err("adc-tm req_sts check failed\n");
return rc;
}
- rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
- sensor_mask, false);
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_ADC_TM_MULTI_MEAS_EN, sensor_mask, false);
if (rc < 0) {
pr_err("multi measurement update failed\n");
return rc;
}
- rc = qpnp_adc_tm_enable_if_channel_meas();
+ rc = qpnp_adc_tm_enable_if_channel_meas(chip);
if (rc < 0) {
pr_err("re-enabling measurement failed\n");
return rc;
@@ -800,9 +831,12 @@
int trip, enum thermal_trip_type *type)
{
struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
+ struct qpnp_adc_tm_chip *chip = adc_tm->chip;
- if (!adc_tm || qpnp_adc_tm_check_revision(adc_tm->btm_channel_num)
- || !type || type < 0)
+ if (qpnp_adc_tm_is_valid(chip))
+ return -ENODEV;
+
+ if (qpnp_adc_tm_check_revision(chip, adc_tm->btm_channel_num))
return -EINVAL;
switch (trip) {
@@ -823,15 +857,17 @@
int trip, unsigned long *temp)
{
struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
- struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+ struct qpnp_adc_tm_chip *chip = adc_tm_sensor->chip;
int64_t result = 0;
u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
unsigned int reg, rc = 0, btm_channel_num;
uint16_t reg_low_thr_lsb, reg_low_thr_msb;
uint16_t reg_high_thr_lsb, reg_high_thr_msb;
- if (!adc_tm || qpnp_adc_tm_check_revision(
- adc_tm_sensor->btm_channel_num))
+ if (qpnp_adc_tm_is_valid(chip))
+ return -ENODEV;
+
+ if (qpnp_adc_tm_check_revision(chip, adc_tm_sensor->btm_channel_num))
return -EINVAL;
btm_channel_num = adc_tm_sensor->btm_channel_num;
@@ -842,13 +878,15 @@
switch (trip) {
case ADC_TM_TRIP_HIGH_WARM:
- rc = qpnp_adc_tm_read_reg(reg_low_thr_lsb, &trip_warm_thr0);
+ rc = qpnp_adc_tm_read_reg(chip, reg_low_thr_lsb,
+ &trip_warm_thr0);
if (rc) {
pr_err("adc-tm low_thr_lsb err\n");
return rc;
}
- rc = qpnp_adc_tm_read_reg(reg_low_thr_msb, &trip_warm_thr1);
+ rc = qpnp_adc_tm_read_reg(chip, reg_low_thr_msb,
+ &trip_warm_thr1);
if (rc) {
pr_err("adc-tm low_thr_msb err\n");
return rc;
@@ -856,13 +894,15 @@
reg = (trip_warm_thr1 << 8) | trip_warm_thr0;
break;
case ADC_TM_TRIP_LOW_COOL:
- rc = qpnp_adc_tm_read_reg(reg_high_thr_lsb, &trip_cool_thr0);
+ rc = qpnp_adc_tm_read_reg(chip, reg_high_thr_lsb,
+ &trip_cool_thr0);
if (rc) {
pr_err("adc-tm_tm high_thr_lsb err\n");
return rc;
}
- rc = qpnp_adc_tm_read_reg(reg_high_thr_msb, &trip_cool_thr1);
+ rc = qpnp_adc_tm_read_reg(chip, reg_high_thr_msb,
+ &trip_cool_thr1);
if (rc) {
pr_err("adc-tm_tm high_thr_lsb err\n");
return rc;
@@ -873,7 +913,8 @@
return -EINVAL;
}
- rc = qpnp_adc_tm_scale_voltage_therm_pu2(reg, &result);
+ rc = qpnp_adc_tm_scale_voltage_therm_pu2(chip->vadc_dev, reg,
+ &result);
if (rc < 0) {
pr_err("Failed to lookup the therm thresholds\n");
return rc;
@@ -887,19 +928,21 @@
static int qpnp_adc_tm_set_trip_temp(struct thermal_zone_device *thermal,
int trip, long temp)
{
- struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
- struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+ struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
+ struct qpnp_adc_tm_chip *chip = adc_tm->chip;
struct qpnp_adc_tm_config tm_config;
u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
uint16_t reg_low_thr_lsb, reg_low_thr_msb;
uint16_t reg_high_thr_lsb, reg_high_thr_msb;
int rc = 0, btm_channel_num;
- if (!adc_tm || qpnp_adc_tm_check_revision(
- adc_tm_sensor->btm_channel_num))
+ if (qpnp_adc_tm_is_valid(chip))
+ return -ENODEV;
+
+ if (qpnp_adc_tm_check_revision(chip, adc_tm->btm_channel_num))
return -EINVAL;
- tm_config.channel = adc_tm_sensor->vadc_channel_num;
+ tm_config.channel = adc_tm->vadc_channel_num;
switch (trip) {
case ADC_TM_TRIP_HIGH_WARM:
tm_config.high_thr_temp = temp;
@@ -913,7 +956,7 @@
pr_debug("requested a high - %d and low - %d with trip - %d\n",
tm_config.high_thr_temp, tm_config.low_thr_temp, trip);
- rc = qpnp_adc_tm_scale_therm_voltage_pu2(&tm_config);
+ rc = qpnp_adc_tm_scale_therm_voltage_pu2(chip->vadc_dev, &tm_config);
if (rc < 0) {
pr_err("Failed to lookup the adc-tm thresholds\n");
return rc;
@@ -924,7 +967,7 @@
trip_cool_thr0 = ((tm_config.high_thr_voltage << 24) >> 24);
trip_cool_thr1 = ((tm_config.high_thr_voltage << 16) >> 24);
- btm_channel_num = adc_tm_sensor->btm_channel_num;
+ btm_channel_num = adc_tm->btm_channel_num;
reg_low_thr_lsb = adc_tm_data[btm_channel_num].low_thr_lsb_addr;
reg_low_thr_msb = adc_tm_data[btm_channel_num].low_thr_msb_addr;
reg_high_thr_lsb = adc_tm_data[btm_channel_num].high_thr_lsb_addr;
@@ -932,32 +975,36 @@
switch (trip) {
case ADC_TM_TRIP_HIGH_WARM:
- rc = qpnp_adc_tm_write_reg(reg_low_thr_lsb, trip_cool_thr0);
+ rc = qpnp_adc_tm_write_reg(chip, reg_low_thr_lsb,
+ trip_cool_thr0);
if (rc) {
pr_err("adc-tm_tm read threshold err\n");
return rc;
}
- rc = qpnp_adc_tm_write_reg(reg_low_thr_msb, trip_cool_thr1);
+ rc = qpnp_adc_tm_write_reg(chip, reg_low_thr_msb,
+ trip_cool_thr1);
if (rc) {
pr_err("adc-tm_tm read threshold err\n");
return rc;
}
- adc_tm_sensor->low_thr = tm_config.high_thr_voltage;
+ adc_tm->low_thr = tm_config.high_thr_voltage;
break;
case ADC_TM_TRIP_LOW_COOL:
- rc = qpnp_adc_tm_write_reg(reg_high_thr_lsb, trip_warm_thr0);
+ rc = qpnp_adc_tm_write_reg(chip, reg_high_thr_lsb,
+ trip_warm_thr0);
if (rc) {
pr_err("adc-tm_tm read threshold err\n");
return rc;
}
- rc = qpnp_adc_tm_write_reg(reg_high_thr_msb, trip_warm_thr1);
+ rc = qpnp_adc_tm_write_reg(chip, reg_high_thr_msb,
+ trip_warm_thr1);
if (rc) {
pr_err("adc-tm_tm read threshold err\n");
return rc;
}
- adc_tm_sensor->high_thr = tm_config.low_thr_voltage;
+ adc_tm->high_thr = tm_config.low_thr_voltage;
break;
default:
return -EINVAL;
@@ -1032,11 +1079,15 @@
int trip, enum thermal_trip_activation_mode mode)
{
struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
+ struct qpnp_adc_tm_chip *chip = adc_tm->chip;
int rc = 0, sensor_mask = 0;
u8 thr_int_en = 0;
bool state = false;
- if (!adc_tm || qpnp_adc_tm_check_revision(adc_tm->btm_channel_num))
+ if (qpnp_adc_tm_is_valid(chip))
+ return -ENODEV;
+
+ if (qpnp_adc_tm_check_revision(chip, adc_tm->btm_channel_num))
return -EINVAL;
if (mode == THERMAL_TRIP_ACTIVATION_ENABLED)
@@ -1051,7 +1102,7 @@
/* low_thr (lower voltage) for higher temp */
thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
low_thr_int_chan_en;
- rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_LOW_THR_INT_EN,
+ rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
sensor_mask, state);
if (rc)
pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
@@ -1060,7 +1111,7 @@
/* high_thr (higher voltage) for cooler temp */
thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
high_thr_int_chan_en;
- rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
+ rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
sensor_mask, state);
if (rc)
pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
@@ -1072,32 +1123,31 @@
return rc;
}
-static int qpnp_adc_tm_read_status(void)
+static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip)
{
- struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
u8 status_low = 0, status_high = 0, qpnp_adc_tm_meas_en = 0;
u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0;
u8 sensor_mask = 0;
int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0, btm_chan_num;
- if (!adc_tm || !adc_tm->adc_tm_initialized)
+ if (qpnp_adc_tm_is_valid(chip))
return -ENODEV;
- mutex_lock(&adc_tm->adc->adc_lock);
+ mutex_lock(&chip->adc->adc_lock);
- rc = qpnp_adc_tm_req_sts_check();
+ rc = qpnp_adc_tm_req_sts_check(chip);
if (rc) {
pr_err("adc-tm-tm req sts check failed with %d\n", rc);
goto fail;
}
- rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_LOW, &status_low);
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS_LOW, &status_low);
if (rc) {
pr_err("adc-tm-tm read status low failed with %d\n", rc);
goto fail;
}
- rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_HIGH, &status_high);
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS_HIGH, &status_high);
if (rc) {
pr_err("adc-tm-tm read status high failed with %d\n", rc);
goto fail;
@@ -1105,7 +1155,7 @@
/* Check which interrupt threshold is lower and measure against the
* enabled channel */
- rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MULTI_MEAS_EN,
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
&qpnp_adc_tm_meas_en);
if (rc) {
pr_err("adc-tm-tm read status high failed with %d\n", rc);
@@ -1117,37 +1167,37 @@
if (adc_tm_high_enable) {
sensor_notify_num = adc_tm_high_enable;
- while (i < adc_tm->max_channels_available) {
+ while (i < chip->max_channels_available) {
if ((sensor_notify_num & 0x1) == 1)
sensor_num = i;
sensor_notify_num >>= 1;
i++;
}
- btm_chan_num = adc_tm->sensor[sensor_num].btm_channel_num;
+ btm_chan_num = chip->sensor[sensor_num].btm_channel_num;
pr_debug("high:sen:%d, hs:0x%x, ls:0x%x, meas_en:0x%x\n",
sensor_num, adc_tm_high_enable, adc_tm_low_enable,
qpnp_adc_tm_meas_en);
- if (!adc_tm->sensor[sensor_num].thermal_node) {
+ if (!chip->sensor[sensor_num].thermal_node) {
/* For non thermal registered clients
such as usb_id, vbatt, pmic_therm */
sensor_mask = 1 << sensor_num;
pr_debug("non thermal node - mask:%x\n", sensor_mask);
- rc = qpnp_adc_tm_reg_update(
+ rc = qpnp_adc_tm_reg_update(chip,
QPNP_ADC_TM_HIGH_THR_INT_EN,
sensor_mask, false);
if (rc < 0) {
pr_err("high threshold int read failed\n");
goto fail;
}
- adc_tm->sensor[sensor_num].high_thr_notify = true;
+ chip->sensor[sensor_num].high_thr_notify = true;
} else {
/* Uses the thermal sysfs registered device to disable
the corresponding high voltage threshold which
is triggered by low temp */
pr_debug("thermal node with mask:%x\n", sensor_mask);
rc = qpnp_adc_tm_activate_trip_type(
- adc_tm->sensor[sensor_num].tz_dev,
+ chip->sensor[sensor_num].tz_dev,
ADC_TM_TRIP_LOW_COOL,
THERMAL_TRIP_ACTIVATION_DISABLED);
if (rc < 0) {
@@ -1160,37 +1210,37 @@
if (adc_tm_low_enable) {
sensor_notify_num = adc_tm_low_enable;
i = 0;
- while (i < adc_tm->max_channels_available) {
+ while (i < chip->max_channels_available) {
if ((sensor_notify_num & 0x1) == 1)
sensor_num = i;
sensor_notify_num >>= 1;
i++;
}
- btm_chan_num = adc_tm->sensor[sensor_num].btm_channel_num;
+ btm_chan_num = chip->sensor[sensor_num].btm_channel_num;
pr_debug("low:sen:%d, hs:0x%x, ls:0x%x, meas_en:0x%x\n",
sensor_num, adc_tm_high_enable, adc_tm_low_enable,
qpnp_adc_tm_meas_en);
- if (!adc_tm->sensor[sensor_num].thermal_node) {
+ if (!chip->sensor[sensor_num].thermal_node) {
/* For non thermal registered clients
such as usb_id, vbatt, pmic_therm */
pr_debug("non thermal node - mask:%x\n", sensor_mask);
sensor_mask = 1 << sensor_num;
- rc = qpnp_adc_tm_reg_update(
+ rc = qpnp_adc_tm_reg_update(chip,
QPNP_ADC_TM_LOW_THR_INT_EN,
sensor_mask, false);
if (rc < 0) {
pr_err("low threshold int read failed\n");
goto fail;
}
- adc_tm->sensor[sensor_num].low_thr_notify = true;
+ chip->sensor[sensor_num].low_thr_notify = true;
} else {
/* Uses the thermal sysfs registered device to disable
the corresponding low voltage threshold which
is triggered by high temp */
pr_debug("thermal node with mask:%x\n", sensor_mask);
rc = qpnp_adc_tm_activate_trip_type(
- adc_tm->sensor[sensor_num].tz_dev,
+ chip->sensor[sensor_num].tz_dev,
ADC_TM_TRIP_HIGH_WARM,
THERMAL_TRIP_ACTIVATION_DISABLED);
if (rc < 0) {
@@ -1201,14 +1251,14 @@
}
if (adc_tm_high_enable || adc_tm_low_enable) {
- rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
+ rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
sensor_mask, false);
if (rc < 0) {
pr_err("multi meas disable for channel failed\n");
goto fail;
}
- rc = qpnp_adc_tm_enable_if_channel_meas();
+ rc = qpnp_adc_tm_enable_if_channel_meas(chip);
if (rc < 0) {
pr_err("re-enabling measurement failed\n");
return rc;
@@ -1218,62 +1268,67 @@
sensor_mask);
fail:
- mutex_unlock(&adc_tm->adc->adc_lock);
+ mutex_unlock(&chip->adc->adc_lock);
if (adc_tm_high_enable || adc_tm_low_enable)
- schedule_work(&adc_tm->sensor[sensor_num].work);
+ schedule_work(&chip->sensor[sensor_num].work);
return rc;
}
static void qpnp_adc_tm_high_thr_work(struct work_struct *work)
{
+ struct qpnp_adc_tm_chip *chip = container_of(work,
+ struct qpnp_adc_tm_chip, trigger_high_thr_work);
int rc;
- rc = qpnp_adc_tm_read_status();
+ rc = qpnp_adc_tm_read_status(chip);
if (rc < 0)
pr_err("adc-tm high thr work failed\n");
return;
}
-DECLARE_WORK(trigger_completion_adc_tm_high_thr_work,
- qpnp_adc_tm_high_thr_work);
static irqreturn_t qpnp_adc_tm_high_thr_isr(int irq, void *data)
{
- qpnp_adc_tm_disable();
+ struct qpnp_adc_tm_chip *chip = data;
- schedule_work(&trigger_completion_adc_tm_high_thr_work);
+ qpnp_adc_tm_disable(chip);
+
+ schedule_work(&chip->trigger_high_thr_work);
return IRQ_HANDLED;
}
static void qpnp_adc_tm_low_thr_work(struct work_struct *work)
{
+ struct qpnp_adc_tm_chip *chip = container_of(work,
+ struct qpnp_adc_tm_chip, trigger_low_thr_work);
int rc;
- rc = qpnp_adc_tm_read_status();
+ rc = qpnp_adc_tm_read_status(chip);
if (rc < 0)
pr_err("adc-tm low thr work failed\n");
return;
}
-DECLARE_WORK(trigger_completion_adc_tm_low_thr_work, qpnp_adc_tm_low_thr_work);
static irqreturn_t qpnp_adc_tm_low_thr_isr(int irq, void *data)
{
- qpnp_adc_tm_disable();
+ struct qpnp_adc_tm_chip *chip = data;
- schedule_work(&trigger_completion_adc_tm_low_thr_work);
+ qpnp_adc_tm_disable(chip);
+
+ schedule_work(&chip->trigger_low_thr_work);
return IRQ_HANDLED;
}
-static irqreturn_t qpnp_adc_tm_isr(int irq, void *dev_id)
+static irqreturn_t qpnp_adc_tm_isr(int irq, void *data)
{
- struct qpnp_adc_tm_drv *adc_tm = dev_id;
+ struct qpnp_adc_tm_chip *chip = data;
- complete(&adc_tm->adc->adc_rslt_completion);
+ complete(&chip->adc->adc_rslt_completion);
return IRQ_HANDLED;
}
@@ -1282,10 +1337,12 @@
unsigned long *temp)
{
struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
+ struct qpnp_adc_tm_chip *chip = adc_tm_sensor->chip;
struct qpnp_vadc_result result;
int rc = 0;
- rc = qpnp_vadc_read(adc_tm_sensor->vadc_channel_num, &result);
+ rc = qpnp_vadc_read(chip->vadc_dev,
+ adc_tm_sensor->vadc_channel_num, &result);
if (rc)
return rc;
@@ -1304,14 +1361,14 @@
.set_trip_temp = qpnp_adc_tm_set_trip_temp,
};
-int32_t qpnp_adc_tm_channel_measure(struct qpnp_adc_tm_btm_param *param)
+int32_t qpnp_adc_tm_channel_measure(struct qpnp_adc_tm_chip *chip,
+ struct qpnp_adc_tm_btm_param *param)
{
- struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
uint32_t channel, dt_index = 0, scale_type = 0;
int rc = 0, i = 0;
bool chan_found = false;
- if (!adc_tm || !adc_tm->adc_tm_initialized)
+ if (qpnp_adc_tm_is_valid(chip))
return -ENODEV;
if (param->threshold_notification == NULL) {
@@ -1319,11 +1376,11 @@
return -EINVAL;
}
- mutex_lock(&adc_tm->adc->adc_lock);
+ mutex_lock(&chip->adc->adc_lock);
channel = param->channel;
- while (i < adc_tm->max_channels_available) {
- if (adc_tm->adc->adc_channels[i].channel_num ==
+ while (i < chip->max_channels_available) {
+ if (chip->adc->adc_channels[i].channel_num ==
channel) {
dt_index = i;
chan_found = true;
@@ -1338,12 +1395,12 @@
goto fail_unlock;
}
- rc = qpnp_adc_tm_check_revision(
- adc_tm->sensor[dt_index].btm_channel_num);
+ rc = qpnp_adc_tm_check_revision(chip,
+ chip->sensor[dt_index].btm_channel_num);
if (rc < 0)
goto fail_unlock;
- scale_type = adc_tm->adc->adc_channels[dt_index].adc_scale_fn;
+ scale_type = chip->adc->adc_channels[dt_index].adc_scale_fn;
if (scale_type >= SCALE_RSCALE_NONE) {
rc = -EBADF;
goto fail_unlock;
@@ -1351,155 +1408,158 @@
pr_debug("channel:%d, scale_type:%d, dt_idx:%d",
channel, scale_type, dt_index);
- adc_tm->adc->amux_prop->amux_channel = channel;
- adc_tm->adc->amux_prop->decimation =
- adc_tm->adc->adc_channels[dt_index].adc_decimation;
- adc_tm->adc->amux_prop->hw_settle_time =
- adc_tm->adc->adc_channels[dt_index].hw_settle_time;
- adc_tm->adc->amux_prop->fast_avg_setup =
- adc_tm->adc->adc_channels[dt_index].fast_avg_setup;
- adc_tm->adc->amux_prop->mode_sel =
+ chip->adc->amux_prop->amux_channel = channel;
+ chip->adc->amux_prop->decimation =
+ chip->adc->adc_channels[dt_index].adc_decimation;
+ chip->adc->amux_prop->hw_settle_time =
+ chip->adc->adc_channels[dt_index].hw_settle_time;
+ chip->adc->amux_prop->fast_avg_setup =
+ chip->adc->adc_channels[dt_index].fast_avg_setup;
+ chip->adc->amux_prop->mode_sel =
ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
- adc_tm->adc->amux_prop->chan_prop->meas_interval1 =
+ chip->adc->amux_prop->chan_prop->meas_interval1 =
ADC_MEAS1_INTERVAL_1S;
- adc_tm_rscale_fn[scale_type].chan(param,
- &adc_tm->adc->amux_prop->chan_prop->low_thr,
- &adc_tm->adc->amux_prop->chan_prop->high_thr);
- adc_tm->adc->amux_prop->chan_prop->tm_channel_select =
- adc_tm->sensor[dt_index].btm_channel_num;
- adc_tm->adc->amux_prop->chan_prop->timer_select =
+ adc_tm_rscale_fn[scale_type].chan(chip->vadc_dev, param,
+ &chip->adc->amux_prop->chan_prop->low_thr,
+ &chip->adc->amux_prop->chan_prop->high_thr);
+ chip->adc->amux_prop->chan_prop->tm_channel_select =
+ chip->sensor[dt_index].btm_channel_num;
+ chip->adc->amux_prop->chan_prop->timer_select =
ADC_MEAS_TIMER_SELECT1;
- adc_tm->adc->amux_prop->chan_prop->state_request =
+ chip->adc->amux_prop->chan_prop->state_request =
param->state_request;
- rc = qpnp_adc_tm_configure(adc_tm->adc->amux_prop);
+ rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop);
if (rc) {
pr_err("adc-tm configure failed with %d\n", rc);
goto fail_unlock;
}
- adc_tm->sensor[dt_index].btm_param = param;
- adc_tm->sensor[dt_index].scale_type = scale_type;
+ chip->sensor[dt_index].btm_param = param;
+ chip->sensor[dt_index].scale_type = scale_type;
fail_unlock:
- mutex_unlock(&adc_tm->adc->adc_lock);
+ mutex_unlock(&chip->adc->adc_lock);
return rc;
}
EXPORT_SYMBOL(qpnp_adc_tm_channel_measure);
-int32_t qpnp_adc_tm_disable_chan_meas(struct qpnp_adc_tm_btm_param *param)
+int32_t qpnp_adc_tm_disable_chan_meas(struct qpnp_adc_tm_chip *chip,
+ struct qpnp_adc_tm_btm_param *param)
{
- struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
uint32_t channel, dt_index = 0, btm_chan_num;
u8 sensor_mask = 0;
int rc = 0;
- if (!adc_tm || !adc_tm->adc_tm_initialized)
+ if (qpnp_adc_tm_is_valid(chip))
return -ENODEV;
- mutex_lock(&adc_tm->adc->adc_lock);
+ mutex_lock(&chip->adc->adc_lock);
/* Disable bank */
- rc = qpnp_adc_tm_disable();
+ rc = qpnp_adc_tm_disable(chip);
if (rc < 0) {
pr_err("adc-tm disable failed\n");
goto fail;
}
/* Check if a conversion is in progress */
- rc = qpnp_adc_tm_req_sts_check();
+ rc = qpnp_adc_tm_req_sts_check(chip);
if (rc < 0) {
pr_err("adc-tm req_sts check failed\n");
goto fail;
}
channel = param->channel;
- while ((adc_tm->adc->adc_channels[dt_index].channel_num
- != channel) && (dt_index < adc_tm->max_channels_available))
+ while ((chip->adc->adc_channels[dt_index].channel_num
+ != channel) && (dt_index < chip->max_channels_available))
dt_index++;
- if (dt_index >= adc_tm->max_channels_available) {
+ if (dt_index >= chip->max_channels_available) {
pr_err("not a valid ADC_TMN channel\n");
rc = -EINVAL;
goto fail;
}
- btm_chan_num = adc_tm->sensor[dt_index].btm_channel_num;
- sensor_mask = 1 << adc_tm->sensor[dt_index].sensor_num;
+ btm_chan_num = chip->sensor[dt_index].btm_channel_num;
+ sensor_mask = 1 << chip->sensor[dt_index].sensor_num;
- rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_LOW_THR_INT_EN,
+ rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
sensor_mask, false);
if (rc < 0) {
pr_err("low threshold int write failed\n");
goto fail;
}
- rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
+ rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
sensor_mask, false);
if (rc < 0) {
pr_err("high threshold int enable failed\n");
goto fail;
}
- rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
+ rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
sensor_mask, false);
if (rc < 0) {
pr_err("multi measurement en failed\n");
goto fail;
}
- rc = qpnp_adc_tm_enable_if_channel_meas();
+ rc = qpnp_adc_tm_enable_if_channel_meas(chip);
if (rc < 0)
pr_err("re-enabling measurement failed\n");
fail:
- mutex_unlock(&adc_tm->adc->adc_lock);
+ mutex_unlock(&chip->adc->adc_lock);
return rc;
}
EXPORT_SYMBOL(qpnp_adc_tm_disable_chan_meas);
-int32_t qpnp_adc_tm_usbid_configure(struct qpnp_adc_tm_btm_param *param)
+int32_t qpnp_adc_tm_usbid_configure(struct qpnp_adc_tm_chip *chip,
+ struct qpnp_adc_tm_btm_param *param)
{
param->channel = LR_MUX10_PU2_AMUX_USB_ID_LV;
- return qpnp_adc_tm_channel_measure(param);
+ return qpnp_adc_tm_channel_measure(chip, param);
}
EXPORT_SYMBOL(qpnp_adc_tm_usbid_configure);
-int32_t qpnp_adc_tm_usbid_end(void)
+int32_t qpnp_adc_tm_usbid_end(struct qpnp_adc_tm_chip *chip)
{
struct qpnp_adc_tm_btm_param param;
- return qpnp_adc_tm_disable_chan_meas(¶m);
+ return qpnp_adc_tm_disable_chan_meas(chip, ¶m);
}
EXPORT_SYMBOL(qpnp_adc_tm_usbid_end);
-int32_t qpnp_adc_tm_is_ready(void)
+struct qpnp_adc_tm_chip *qpnp_get_adc_tm(struct device *dev, const char *name)
{
- struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+ struct qpnp_adc_tm_chip *chip;
+ struct device_node *node = NULL;
+ char prop_name[QPNP_MAX_PROP_NAME_LEN];
- if (!adc_tm || !adc_tm->adc_tm_initialized)
- return -EPROBE_DEFER;
- else
- return 0;
+ snprintf(prop_name, QPNP_MAX_PROP_NAME_LEN, "qcom,%s-adc_tm", name);
+
+ node = of_parse_phandle(dev->of_node, prop_name, 0);
+ if (node == NULL)
+ return ERR_PTR(-ENODEV);
+
+ list_for_each_entry(chip, &qpnp_adc_tm_device_list, list)
+ if (chip->adc->spmi->dev.of_node == node)
+ return chip;
+
+ return ERR_PTR(-EPROBE_DEFER);
}
-EXPORT_SYMBOL(qpnp_adc_tm_is_ready);
+EXPORT_SYMBOL(qpnp_get_adc_tm);
static int __devinit qpnp_adc_tm_probe(struct spmi_device *spmi)
{
struct device_node *node = spmi->dev.of_node, *child;
- struct qpnp_adc_tm_drv *adc_tm;
+ struct qpnp_adc_tm_chip *chip;
struct qpnp_adc_drv *adc_qpnp;
- int32_t count_adc_channel_list = 0, rc, sen_idx = 0;
+ int32_t count_adc_channel_list = 0, rc, sen_idx = 0, i = 0;
u8 thr_init = 0;
-
- if (!node)
- return -EINVAL;
-
- if (qpnp_adc_tm) {
- pr_err("adc-tm already in use\n");
- return -EBUSY;
- }
+ bool thermal_node = false;
for_each_child_of_node(node, child)
count_adc_channel_list++;
@@ -1509,16 +1569,15 @@
return -EINVAL;
}
- adc_tm = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_tm_drv) +
+ chip = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_tm_chip) +
(count_adc_channel_list *
sizeof(struct qpnp_adc_tm_sensor)),
GFP_KERNEL);
- if (!adc_tm) {
+ if (!chip) {
dev_err(&spmi->dev, "Unable to allocate memory\n");
return -ENOMEM;
}
- qpnp_adc_tm = adc_tm;
adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
GFP_KERNEL);
if (!adc_qpnp) {
@@ -1527,67 +1586,74 @@
goto fail;
}
- adc_tm->adc = adc_qpnp;
+ chip->adc = adc_qpnp;
- rc = qpnp_adc_get_devicetree_data(spmi, adc_tm->adc);
+ rc = qpnp_adc_get_devicetree_data(spmi, chip->adc);
if (rc) {
dev_err(&spmi->dev, "failed to read device tree\n");
goto fail;
}
- mutex_init(&adc_tm->adc->adc_lock);
+ mutex_init(&chip->adc->adc_lock);
/* Register the ADC peripheral interrupt */
- adc_tm->adc->adc_high_thr_irq = spmi_get_irq_byname(spmi,
+ chip->adc->adc_high_thr_irq = spmi_get_irq_byname(spmi,
NULL, "high-thr-en-set");
- if (adc_tm->adc->adc_high_thr_irq < 0) {
+ if (chip->adc->adc_high_thr_irq < 0) {
pr_err("Invalid irq\n");
rc = -ENXIO;
goto fail;
}
- adc_tm->adc->adc_low_thr_irq = spmi_get_irq_byname(spmi,
+ chip->adc->adc_low_thr_irq = spmi_get_irq_byname(spmi,
NULL, "low-thr-en-set");
- if (adc_tm->adc->adc_low_thr_irq < 0) {
+ if (chip->adc->adc_low_thr_irq < 0) {
pr_err("Invalid irq\n");
rc = -ENXIO;
goto fail;
}
- rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_irq_eoc,
+ chip->vadc_dev = qpnp_get_vadc(&spmi->dev, "adc_tm");
+ if (IS_ERR(chip->vadc_dev)) {
+ rc = PTR_ERR(chip->vadc_dev);
+ if (rc != -EPROBE_DEFER)
+ pr_err("vadc property missing, rc=%d\n", rc);
+ goto fail;
+ }
+
+ rc = devm_request_irq(&spmi->dev, chip->adc->adc_irq_eoc,
qpnp_adc_tm_isr, IRQF_TRIGGER_RISING,
- "qpnp_adc_tm_interrupt", adc_tm);
+ "qpnp_adc_tm_interrupt", chip);
if (rc) {
dev_err(&spmi->dev,
"failed to request adc irq with error %d\n", rc);
goto fail;
} else {
- enable_irq_wake(adc_tm->adc->adc_irq_eoc);
+ enable_irq_wake(chip->adc->adc_irq_eoc);
}
- rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_high_thr_irq,
+ rc = devm_request_irq(&spmi->dev, chip->adc->adc_high_thr_irq,
qpnp_adc_tm_high_thr_isr,
- IRQF_TRIGGER_RISING, "qpnp_adc_tm_high_interrupt", adc_tm);
+ IRQF_TRIGGER_RISING, "qpnp_adc_tm_high_interrupt", chip);
if (rc) {
dev_err(&spmi->dev, "failed to request adc irq\n");
goto fail;
} else {
- enable_irq_wake(adc_tm->adc->adc_high_thr_irq);
+ enable_irq_wake(chip->adc->adc_high_thr_irq);
}
- rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_low_thr_irq,
+ rc = devm_request_irq(&spmi->dev, chip->adc->adc_low_thr_irq,
qpnp_adc_tm_low_thr_isr,
- IRQF_TRIGGER_RISING, "qpnp_adc_tm_low_interrupt", adc_tm);
+ IRQF_TRIGGER_RISING, "qpnp_adc_tm_low_interrupt", chip);
if (rc) {
dev_err(&spmi->dev, "failed to request adc irq\n");
goto fail;
} else {
- enable_irq_wake(adc_tm->adc->adc_low_thr_irq);
+ enable_irq_wake(chip->adc->adc_low_thr_irq);
}
for_each_child_of_node(node, child) {
char name[25];
int btm_channel_num;
- bool thermal_node = false;
rc = of_property_read_u32(child,
"qcom,btm-channel-number", &btm_channel_num);
@@ -1595,80 +1661,95 @@
pr_err("Invalid btm channel number\n");
goto fail;
}
- adc_tm->sensor[sen_idx].btm_channel_num = btm_channel_num;
- adc_tm->sensor[sen_idx].vadc_channel_num =
- adc_tm->adc->adc_channels[sen_idx].channel_num;
- adc_tm->sensor[sen_idx].sensor_num = sen_idx;
+ chip->sensor[sen_idx].btm_channel_num = btm_channel_num;
+ chip->sensor[sen_idx].vadc_channel_num =
+ chip->adc->adc_channels[sen_idx].channel_num;
+ chip->sensor[sen_idx].sensor_num = sen_idx;
+ chip->sensor[sen_idx].chip = chip;
pr_debug("btm_chan:%x, vadc_chan:%x\n", btm_channel_num,
- adc_tm->adc->adc_channels[sen_idx].channel_num);
+ chip->adc->adc_channels[sen_idx].channel_num);
thermal_node = of_property_read_bool(child,
"qcom,thermal-node");
if (thermal_node) {
/* Register with the thermal zone */
pr_debug("thermal node%x\n", btm_channel_num);
- adc_tm->sensor[sen_idx].mode = THERMAL_DEVICE_DISABLED;
- adc_tm->sensor[sen_idx].thermal_node = true;
+ chip->sensor[sen_idx].mode = THERMAL_DEVICE_DISABLED;
+ chip->sensor[sen_idx].thermal_node = true;
snprintf(name, sizeof(name),
- adc_tm->adc->adc_channels[sen_idx].name);
- adc_tm->sensor[sen_idx].meas_interval =
+ chip->adc->adc_channels[sen_idx].name);
+ chip->sensor[sen_idx].meas_interval =
QPNP_ADC_TM_MEAS_INTERVAL;
- adc_tm->sensor[sen_idx].low_thr =
+ chip->sensor[sen_idx].low_thr =
QPNP_ADC_TM_M0_LOW_THR;
- adc_tm->sensor[sen_idx].high_thr =
+ chip->sensor[sen_idx].high_thr =
QPNP_ADC_TM_M0_HIGH_THR;
- adc_tm->sensor[sen_idx].tz_dev =
+ chip->sensor[sen_idx].tz_dev =
thermal_zone_device_register(name,
ADC_TM_TRIP_NUM,
- &adc_tm->sensor[sen_idx],
+ &chip->sensor[sen_idx],
&qpnp_adc_tm_thermal_ops, 0, 0, 0, 0);
- if (IS_ERR(adc_tm->sensor[sen_idx].tz_dev))
+ if (IS_ERR(chip->sensor[sen_idx].tz_dev))
pr_err("thermal device register failed.\n");
}
- INIT_WORK(&adc_tm->sensor[sen_idx].work, notify_adc_tm_fn);
+ INIT_WORK(&chip->sensor[sen_idx].work, notify_adc_tm_fn);
sen_idx++;
}
- adc_tm->max_channels_available = count_adc_channel_list;
- dev_set_drvdata(&spmi->dev, adc_tm);
- rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_HIGH_THR_INT_EN, thr_init);
+ chip->max_channels_available = count_adc_channel_list;
+ INIT_WORK(&chip->trigger_high_thr_work, qpnp_adc_tm_high_thr_work);
+ INIT_WORK(&chip->trigger_low_thr_work, qpnp_adc_tm_low_thr_work);
+ dev_set_drvdata(&spmi->dev, chip);
+ list_add(&chip->list, &qpnp_adc_tm_device_list);
+
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
+ thr_init);
if (rc < 0) {
pr_err("high thr init failed\n");
goto fail;
}
- rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_LOW_THR_INT_EN, thr_init);
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
+ thr_init);
if (rc < 0) {
pr_err("low thr init failed\n");
goto fail;
}
- rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MULTI_MEAS_EN, thr_init);
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
+ thr_init);
if (rc < 0) {
pr_err("multi meas en failed\n");
goto fail;
}
- adc_tm->adc_tm_initialized = true;
-
pr_debug("OK\n");
return 0;
fail:
- qpnp_adc_tm = NULL;
+ for_each_child_of_node(node, child) {
+ thermal_node = of_property_read_bool(child,
+ "qcom,thermal-node");
+ if (thermal_node)
+ thermal_zone_device_unregister(chip->sensor[i].tz_dev);
+ i++;
+ }
+ dev_set_drvdata(&spmi->dev, NULL);
return rc;
}
static int __devexit qpnp_adc_tm_remove(struct spmi_device *spmi)
{
- struct qpnp_adc_tm_drv *adc_tm = dev_get_drvdata(&spmi->dev);
- struct device_node *node = spmi->dev.of_node;
- struct device_node *child;
+ struct qpnp_adc_tm_chip *chip = dev_get_drvdata(&spmi->dev);
+ struct device_node *node = spmi->dev.of_node, *child;
+ bool thermal_node = false;
int i = 0;
for_each_child_of_node(node, child) {
- thermal_zone_device_unregister(adc_tm->sensor[i].tz_dev);
+ thermal_node = of_property_read_bool(child,
+ "qcom,thermal-node");
+ if (thermal_node)
+ thermal_zone_device_unregister(chip->sensor[i].tz_dev);
i++;
}
- adc_tm->adc_tm_initialized = false;
dev_set_drvdata(&spmi->dev, NULL);
return 0;
diff --git a/drivers/thermal/qpnp-temp-alarm.c b/drivers/thermal/qpnp-temp-alarm.c
index 499d67e..36b84c8 100644
--- a/drivers/thermal/qpnp-temp-alarm.c
+++ b/drivers/thermal/qpnp-temp-alarm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -93,6 +93,7 @@
enum qpnp_vadc_channels adc_channel;
u16 base_addr;
bool allow_software_override;
+ struct qpnp_vadc_chip *vadc_dev;
};
/* Delay between TEMP_STAT IRQ going high and status value changing in ms. */
@@ -160,7 +161,7 @@
struct qpnp_vadc_result adc_result;
int rc;
- rc = qpnp_vadc_read(chip->adc_channel, &adc_result);
+ rc = qpnp_vadc_read(chip->vadc_dev, chip->adc_channel, &adc_result);
if (!rc)
chip->temperature = adc_result.physical;
else
@@ -543,9 +544,12 @@
__func__, chip->adc_channel);
} else {
chip->adc_type = QPNP_TM_ADC_QPNP_ADC;
- rc = qpnp_vadc_is_ready();
- if (rc) {
- /* Probe retry, do not print an error message */
+ chip->vadc_dev = qpnp_get_vadc(&spmi->dev,
+ "temp_alarm");
+ if (IS_ERR(chip->vadc_dev)) {
+ rc = PTR_ERR(chip->vadc_dev);
+ if (rc != -EPROBE_DEFER)
+ pr_err("vadc property missing\n");
goto err_cancel_work;
}
}
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index c89f6d8..d3ea3be 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -204,6 +204,7 @@
int pmic_id_irq;
struct work_struct id_work;
struct qpnp_adc_tm_btm_param adc_param;
+ struct qpnp_adc_tm_chip *adc_tm_dev;
struct delayed_work init_adc_work;
bool id_adc_detect;
u8 dcd_retries;
@@ -1709,7 +1710,8 @@
}
dcp = ((mdwc->charger.chg_type == DWC3_DCP_CHARGER) ||
- (mdwc->charger.chg_type == DWC3_PROPRIETARY_CHARGER));
+ (mdwc->charger.chg_type == DWC3_PROPRIETARY_CHARGER) ||
+ (mdwc->charger.chg_type == DWC3_FLOATED_CHARGER));
host_bus_suspend = mdwc->host_mode == 1;
if (!dcp && !host_bus_suspend)
@@ -1841,7 +1843,8 @@
}
dcp = ((mdwc->charger.chg_type == DWC3_DCP_CHARGER) ||
- (mdwc->charger.chg_type == DWC3_PROPRIETARY_CHARGER));
+ (mdwc->charger.chg_type == DWC3_PROPRIETARY_CHARGER) ||
+ (mdwc->charger.chg_type == DWC3_FLOATED_CHARGER));
host_bus_suspend = mdwc->host_mode == 1;
if (mdwc->lpm_flags & MDWC3_TCXO_SHUTDOWN) {
@@ -2354,7 +2357,7 @@
dwc3_id_work(&mdwc->id_work);
/* re-arm ADC interrupt */
- qpnp_adc_tm_usbid_configure(&mdwc->adc_param);
+ qpnp_adc_tm_usbid_configure(mdwc->adc_tm_dev, &mdwc->adc_param);
}
static void dwc3_init_adc_work(struct work_struct *w)
@@ -2363,10 +2366,14 @@
init_adc_work.work);
int ret;
- ret = qpnp_adc_tm_is_ready();
- if (ret == -EPROBE_DEFER) {
- queue_delayed_work(system_nrt_wq, to_delayed_work(w),
+ mdwc->adc_tm_dev = qpnp_get_adc_tm(mdwc->dev, "dwc_usb3-adc_tm");
+ if (IS_ERR(mdwc->adc_tm_dev)) {
+ if (PTR_ERR(mdwc->adc_tm_dev) == -EPROBE_DEFER)
+ queue_delayed_work(system_nrt_wq, to_delayed_work(w),
msecs_to_jiffies(100));
+ else
+ mdwc->adc_tm_dev = NULL;
+
return;
}
@@ -2377,7 +2384,7 @@
mdwc->adc_param.btm_ctx = mdwc;
mdwc->adc_param.threshold_notification = dwc3_adc_notification;
- ret = qpnp_adc_tm_usbid_configure(&mdwc->adc_param);
+ ret = qpnp_adc_tm_usbid_configure(mdwc->adc_tm_dev, &mdwc->adc_param);
if (ret) {
dev_err(mdwc->dev, "%s: request ADC error %d\n", __func__, ret);
return;
@@ -2412,7 +2419,7 @@
dwc3_init_adc_work(&mdwc->init_adc_work.work);
return size;
} else if (!strnicmp(buf, "disable", 7)) {
- qpnp_adc_tm_usbid_end();
+ qpnp_adc_tm_usbid_end(mdwc->adc_tm_dev);
mdwc->id_adc_detect = false;
return size;
}
@@ -3042,7 +3049,7 @@
}
if (mdwc->id_adc_detect)
- qpnp_adc_tm_usbid_end();
+ qpnp_adc_tm_usbid_end(mdwc->adc_tm_dev);
if (dwc3_debugfs_root)
debugfs_remove_recursive(dwc3_debugfs_root);
if (mdwc->otg_xceiv) {
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index 0d4d580..d0d9d34 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -727,7 +727,9 @@
work = 1;
break;
case DWC3_FLOATED_CHARGER:
- dotg->charger_retry_count++;
+ if (dotg->charger_retry_count <
+ max_chgr_retry_count)
+ dotg->charger_retry_count++;
/*
* In case of floating charger, if
* retry count equal to max retry count
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index a775459..b0b2f56 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -127,6 +127,8 @@
struct work_struct connect_w;
struct work_struct disconnect_w;
+ struct work_struct suspend_w;
+ struct work_struct resume_w;
};
static struct bam_portmaster {
@@ -542,7 +544,9 @@
struct bam_ch_info *d = &port->data_ch;
int status;
+ spin_lock(&port->port_lock_ul);
if (!port->port_usb) {
+ spin_unlock(&port->port_lock_ul);
pr_err("%s: port->port_usb is NULL", __func__);
return;
}
@@ -551,6 +555,7 @@
status = usb_ep_queue(port->port_usb->out, d->rx_req, GFP_ATOMIC);
if (status)
pr_err("%s: error enqueuing transfer, %d\n", __func__, status);
+ spin_unlock(&port->port_lock_ul);
}
static void gbam_start_endless_tx(struct gbam_port *port)
@@ -558,7 +563,9 @@
struct bam_ch_info *d = &port->data_ch;
int status;
+ spin_lock(&port->port_lock_dl);
if (!port->port_usb) {
+ spin_unlock(&port->port_lock_dl);
pr_err("%s: port->port_usb is NULL", __func__);
return;
}
@@ -567,6 +574,8 @@
status = usb_ep_queue(port->port_usb->in, d->tx_req, GFP_ATOMIC);
if (status)
pr_err("%s: error enqueuing transfer, %d\n", __func__, status);
+ spin_unlock(&port->port_lock_dl);
+
}
static void gbam_stop_endless_rx(struct gbam_port *port)
@@ -574,7 +583,9 @@
struct bam_ch_info *d = &port->data_ch;
int status;
+ spin_lock(&port->port_lock_ul);
if (!port->port_usb) {
+ spin_unlock(&port->port_lock_ul);
pr_err("%s: port->port_usb is NULL", __func__);
return;
}
@@ -583,14 +594,17 @@
status = usb_ep_dequeue(port->port_usb->out, d->rx_req);
if (status)
pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
-
+ spin_unlock(&port->port_lock_ul);
}
+
static void gbam_stop_endless_tx(struct gbam_port *port)
{
struct bam_ch_info *d = &port->data_ch;
int status;
+ spin_lock(&port->port_lock_dl);
if (!port->port_usb) {
+ spin_unlock(&port->port_lock_dl);
pr_err("%s: port->port_usb is NULL", __func__);
return;
}
@@ -599,6 +613,7 @@
status = usb_ep_dequeue(port->port_usb->in, d->tx_req);
if (status)
pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
+ spin_unlock(&port->port_lock_dl);
}
static void gbam_start(void *param, enum usb_bam_pipe_dir dir)
@@ -893,6 +908,46 @@
pr_debug("%s: done\n", __func__);
}
+static int gbam_wake_cb(void *param)
+{
+ struct gbam_port *port = (struct gbam_port *)param;
+ struct bam_ch_info *d;
+ struct f_rmnet *dev;
+
+ dev = port_to_rmnet(port->gr);
+ d = &port->data_ch;
+
+ pr_debug("%s: woken up by peer\n", __func__);
+
+ return usb_gadget_wakeup(dev->cdev->gadget);
+}
+
+static void gbam2bam_suspend_work(struct work_struct *w)
+{
+ struct gbam_port *port = container_of(w, struct gbam_port, suspend_w);
+ struct bam_ch_info *d = &port->data_ch;
+
+ pr_debug("%s: suspend work started\n", __func__);
+
+ usb_bam_register_wake_cb(d->dst_connection_idx, gbam_wake_cb, port);
+ if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+ usb_bam_register_start_stop_cbs(gbam_start, gbam_stop, port);
+ usb_bam_suspend(&d->ipa_params);
+ }
+}
+
+static void gbam2bam_resume_work(struct work_struct *w)
+{
+ struct gbam_port *port = container_of(w, struct gbam_port, resume_w);
+ struct bam_ch_info *d = &port->data_ch;
+
+ pr_debug("%s: resume work started\n", __func__);
+
+ usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL);
+ if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA)
+ usb_bam_resume(&d->ipa_params);
+}
+
static int gbam_peer_reset_cb(void *param)
{
struct gbam_port *port = (struct gbam_port *)param;
@@ -1122,6 +1177,8 @@
INIT_WORK(&port->connect_w, gbam2bam_connect_work);
INIT_WORK(&port->disconnect_w, gbam2bam_disconnect_work);
+ INIT_WORK(&port->suspend_w, gbam2bam_suspend_work);
+ INIT_WORK(&port->resume_w, gbam2bam_resume_work);
/* data ch */
d = &port->data_ch;
@@ -1446,20 +1503,6 @@
return ret;
}
-static int gbam_wake_cb(void *param)
-{
- struct gbam_port *port = (struct gbam_port *)param;
- struct bam_ch_info *d;
- struct f_rmnet *dev;
-
- dev = port_to_rmnet(port->gr);
- d = &port->data_ch;
-
- pr_debug("%s: woken up by peer\n", __func__);
-
- return usb_gadget_wakeup(dev->cdev->gadget);
-}
-
void gbam_suspend(struct grmnet *gr, u8 port_num, enum transport_type trans)
{
struct gbam_port *port;
@@ -1474,11 +1517,7 @@
pr_debug("%s: suspended port %d\n", __func__, port_num);
- usb_bam_register_wake_cb(d->dst_connection_idx, gbam_wake_cb, port);
- if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
- usb_bam_register_start_stop_cbs(gbam_start, gbam_stop, port);
- usb_bam_suspend(&d->ipa_params);
- }
+ queue_work(gbam_wq, &port->suspend_w);
}
void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans)
@@ -1495,7 +1534,5 @@
pr_debug("%s: resumed port %d\n", __func__, port_num);
- usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL);
- if (trans == USB_GADGET_XPORT_BAM2BAM_IPA)
- usb_bam_resume(&d->ipa_params);
+ queue_work(gbam_wq, &port->resume_w);
}
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index 577a4fe..b315605 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -62,10 +62,15 @@
struct work_struct connect_w;
struct work_struct disconnect_w;
+ struct work_struct suspend_w;
+ struct work_struct resume_w;
};
struct bam_data_port *bam2bam_data_ports[BAM2BAM_DATA_N_PORTS];
+static void bam2bam_data_suspend_work(struct work_struct *w);
+static void bam2bam_data_resume_work(struct work_struct *w);
+
/*------------data_path----------------------------*/
static void bam_data_endless_rx_complete(struct usb_ep *ep,
@@ -351,6 +356,8 @@
INIT_WORK(&port->connect_w, bam2bam_data_connect_work);
INIT_WORK(&port->disconnect_w, bam2bam_data_disconnect_work);
+ INIT_WORK(&port->suspend_w, bam2bam_data_suspend_work);
+ INIT_WORK(&port->resume_w, bam2bam_data_resume_work);
/* data ch */
d = &port->data_ch;
@@ -578,12 +585,8 @@
d = &port->data_ch;
pr_debug("%s: suspended port %d\n", __func__, port_num);
- usb_bam_register_wake_cb(d->dst_connection_idx, bam_data_wake_cb, port);
- if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
- usb_bam_register_start_stop_cbs(bam_data_start, bam_data_stop,
- port);
- usb_bam_suspend(&d->ipa_params);
- }
+
+ queue_work(bam_data_wq, &port->suspend_w);
}
void bam_data_resume(u8 port_num)
@@ -596,6 +599,34 @@
d = &port->data_ch;
pr_debug("%s: resumed port %d\n", __func__, port_num);
+
+ queue_work(bam_data_wq, &port->resume_w);
+}
+
+static void bam2bam_data_suspend_work(struct work_struct *w)
+{
+ struct bam_data_port *port =
+ container_of(w, struct bam_data_port, suspend_w);
+ struct bam_data_ch_info *d = &port->data_ch;
+
+ pr_debug("%s: suspend work started\n", __func__);
+
+ usb_bam_register_wake_cb(d->dst_connection_idx, bam_data_wake_cb, port);
+ if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+ usb_bam_register_start_stop_cbs(bam_data_start, bam_data_stop,
+ port);
+ usb_bam_suspend(&d->ipa_params);
+ }
+}
+
+static void bam2bam_data_resume_work(struct work_struct *w)
+{
+ struct bam_data_port *port =
+ container_of(w, struct bam_data_port, resume_w);
+ struct bam_data_ch_info *d = &port->data_ch;
+
+ pr_debug("%s: resume work started\n", __func__);
+
usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL);
if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA)
usb_bam_resume(&d->ipa_params);
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 253658e..d102c22 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -1122,10 +1122,16 @@
u32 cmd;
unsigned long flags;
int retries = 0, ret, cnt = RESET_SIGNAL_TIME_USEC;
+ s32 next_latency = 0;
- if (pdata && pdata->swfi_latency)
- pm_qos_update_request(&mehci->pm_qos_req_dma,
- pdata->swfi_latency + 1);
+ if (pdata && pdata->swfi_latency) {
+ next_latency = pdata->swfi_latency + 1;
+ pm_qos_update_request(&mehci->pm_qos_req_dma, next_latency);
+ if (pdata->standalone_latency)
+ next_latency = pdata->standalone_latency + 1;
+ else
+ next_latency = PM_QOS_DEFAULT_VALUE;
+ }
mehci->bus_reset = 1;
@@ -1196,9 +1202,8 @@
pr_debug("reset completed\n");
fail:
mehci->bus_reset = 0;
- if (pdata && pdata->swfi_latency)
- pm_qos_update_request(&mehci->pm_qos_req_dma,
- PM_QOS_DEFAULT_VALUE);
+ if (next_latency)
+ pm_qos_update_request(&mehci->pm_qos_req_dma, next_latency);
}
static int ehci_hsic_bus_suspend(struct usb_hcd *hcd)
@@ -1229,19 +1234,27 @@
int retry_cnt = 0;
int tight_resume = 0;
struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
+ s32 next_latency = 0;
dbg_log_event(NULL, "Resume RH", 0);
+ if (pdata && pdata->swfi_latency) {
+ next_latency = pdata->swfi_latency + 1;
+ pm_qos_update_request(&mehci->pm_qos_req_dma, next_latency);
+ if (pdata->standalone_latency)
+ next_latency = pdata->standalone_latency + 1;
+ else
+ next_latency = PM_QOS_DEFAULT_VALUE;
+ }
+
/* keep delay between bus states */
if (time_before(jiffies, ehci->next_statechange))
usleep_range(5000, 5000);
spin_lock_irq(&ehci->lock);
if (!HCD_HW_ACCESSIBLE(hcd)) {
- spin_unlock_irq(&ehci->lock);
mehci->resume_status = -ESHUTDOWN;
- complete(&mehci->rt_completion);
- return 0;
+ goto exit;
}
if (unlikely(ehci->debug)) {
@@ -1313,13 +1326,7 @@
&mehci->timer->gptimer1_ctrl);
spin_unlock_irq(&ehci->lock);
- if (pdata && pdata->swfi_latency)
- pm_qos_update_request(&mehci->pm_qos_req_dma,
- pdata->swfi_latency + 1);
wait_for_completion(&mehci->gpt0_completion);
- if (pdata && pdata->standalone_latency)
- pm_qos_update_request(&mehci->pm_qos_req_dma,
- pdata->standalone_latency + 1);
spin_lock_irq(&ehci->lock);
} else {
dbg_log_event(NULL, "FPR: Tightloop", 0);
@@ -1357,9 +1364,11 @@
dbg_log_event(NULL, "FPR: RT-Done", 0);
mehci->resume_status = 1;
+exit:
spin_unlock_irq(&ehci->lock);
-
complete(&mehci->rt_completion);
+ if (next_latency)
+ pm_qos_update_request(&mehci->pm_qos_req_dma, next_latency);
return 0;
}
@@ -1872,6 +1881,8 @@
pdata->phy_sof_workaround = of_property_read_bool(node,
"qcom,phy-sof-workaround");
+ pdata->phy_susp_sof_workaround = of_property_read_bool(node,
+ "qcom,phy-susp-sof-workaround");
pdata->ignore_cal_pad_config = of_property_read_bool(node,
"hsic,ignore-cal-pad-config");
of_property_read_u32(node, "hsic,strobe-pad-offset",
@@ -1978,9 +1989,13 @@
spin_lock_init(&mehci->wakeup_lock);
if (pdata->phy_sof_workaround) {
+ /* Enable ALL workarounds related to PHY SOF bugs */
mehci->ehci.susp_sof_bug = 1;
mehci->ehci.reset_sof_bug = 1;
mehci->ehci.resume_sof_bug = 1;
+ } else if (pdata->phy_susp_sof_workaround) {
+ /* Only SUSP SOF hardware bug exists, rest all not present */
+ mehci->ehci.susp_sof_bug = 1;
}
if (pdata->reset_delay)
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 06e3a1b..9139447 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -4292,11 +4292,27 @@
goto put_core_clk;
}
+ /*
+ * On few platforms USB PHY is fed with sleep clk.
+ * Hence don't fail probe.
+ */
+ motg->sleep_clk = devm_clk_get(&pdev->dev, "sleep_clk");
+ if (IS_ERR(motg->sleep_clk)) {
+ dev_dbg(&pdev->dev, "failed to get sleep_clk\n");
+ } else {
+ ret = clk_prepare_enable(motg->sleep_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "%s failed to vote sleep_clk%d\n",
+ __func__, ret);
+ goto put_pclk;
+ }
+ }
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "failed to get platform resource mem\n");
ret = -ENODEV;
- goto put_pclk;
+ goto disable_sleep_clk;
}
motg->io_res = res;
@@ -4304,7 +4320,7 @@
if (!motg->regs) {
dev_err(&pdev->dev, "ioremap failed\n");
ret = -ENOMEM;
- goto put_pclk;
+ goto disable_sleep_clk;
}
dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs);
@@ -4603,6 +4619,9 @@
msm_xo_put(motg->xo_handle);
free_regs:
iounmap(motg->regs);
+disable_sleep_clk:
+ if (!IS_ERR(motg->sleep_clk))
+ clk_disable_unprepare(motg->sleep_clk);
put_pclk:
clk_put(motg->pclk);
put_core_clk:
@@ -4697,6 +4716,10 @@
} else {
msm_xo_put(motg->xo_handle);
}
+
+ if (!IS_ERR(motg->sleep_clk))
+ clk_disable_unprepare(motg->sleep_clk);
+
msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
msm_hsusb_ldo_init(motg, 0);
regulator_disable(hsusb_vdd);
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 3b0cd20..a575d6d 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -477,7 +477,6 @@
}
ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT;
}
- mdss_dsi_op_mode_config(mipi->mode, pdata);
if (pdata->panel_info.type == MIPI_CMD_PANEL) {
if (mipi->vsync_enable && mipi->hw_vsync_mode
@@ -555,9 +554,9 @@
mdss_dsi_sw_reset(pdata);
mdss_dsi_host_init(mipi, pdata);
+ mdss_dsi_op_mode_config(mipi->mode, pdata);
if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) {
- mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
ret = mdss_dsi_unblank(pdata);
if (ret) {
pr_err("%s: unblank failed\n", __func__);
@@ -586,6 +585,8 @@
switch (event) {
case MDSS_EVENT_UNBLANK:
rc = mdss_dsi_on(pdata);
+ mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode,
+ pdata);
if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE)
rc = mdss_dsi_unblank(pdata);
break;
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 055f233..e48d0d2 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -1157,11 +1157,21 @@
dchdr = &cm->dchdr;
mdss_dsi_buf_reserve(tp, len);
len = mdss_dsi_cmd_dma_add(tp, cm);
+ if (!len) {
+ pr_err("%s: failed to call cmd_dma_add\n", __func__);
+ return -EINVAL;
+ }
tot += len;
if (dchdr->last) {
tp->data = tp->start; /* begin of buf */
mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
- mdss_dsi_cmd_dma_tx(ctrl, tp);
+ len = mdss_dsi_cmd_dma_tx(ctrl, tp);
+ if (IS_ERR_VALUE(len)) {
+ mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM);
+ pr_err("%s: failed to call cmd_dma_tx for cmd = 0x%x\n",
+ __func__, cmds->payload[0]);
+ return -EINVAL;
+ }
if (dchdr->wait)
usleep(dchdr->wait * 1000);
@@ -1181,7 +1191,7 @@
struct dsi_cmd_desc *cmds, int cnt)
{
u32 dsi_ctrl, data;
- int video_mode;
+ int video_mode, ret = 0;
u32 left_dsi_ctrl = 0;
bool left_ctrl_restore = false;
@@ -1221,7 +1231,12 @@
MIPI_OUTP((ctrl->ctrl_base) + 0x0004, data);
}
- mdss_dsi_cmds2buf_tx(ctrl, cmds, cnt);
+ ret = mdss_dsi_cmds2buf_tx(ctrl, cmds, cnt);
+ if (IS_ERR_VALUE(ret)) {
+ pr_err("%s: failed to call\n",
+ __func__);
+ cnt = -EINVAL;
+ }
if (left_ctrl_restore)
MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
@@ -1257,7 +1272,7 @@
int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl,
struct dsi_cmd_desc *cmds, int rlen, u32 rx_flags)
{
- int cnt, len, diff, pkt_size;
+ int cnt, len, diff, pkt_size, ret = 0;
struct dsi_buf *tp, *rp;
int no_max_pkt_size;
char cmd;
@@ -1334,19 +1349,44 @@
/* packet size need to be set at every read */
pkt_size = len;
max_pktsize[0] = pkt_size;
- mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
mdss_dsi_buf_init(tp);
- mdss_dsi_cmd_dma_add(tp, &pkt_size_cmd);
- mdss_dsi_cmd_dma_tx(ctrl, tp);
+ ret = mdss_dsi_cmd_dma_add(tp, &pkt_size_cmd);
+ if (!ret) {
+ pr_err("%s: failed to call\n",
+ __func__);
+ rp->len = 0;
+ goto end;
+ }
+ mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
+ ret = mdss_dsi_cmd_dma_tx(ctrl, tp);
+ if (IS_ERR_VALUE(ret)) {
+ mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM);
+ pr_err("%s: failed to call\n",
+ __func__);
+ rp->len = 0;
+ goto end;
+ }
pr_debug("%s: Max packet size sent\n", __func__);
}
+ mdss_dsi_buf_init(tp);
+ ret = mdss_dsi_cmd_dma_add(tp, cmds);
+ if (!ret) {
+ pr_err("%s: failed to call cmd_dma_add for cmd = 0x%x\n",
+ __func__, cmds->payload[0]);
+ rp->len = 0;
+ goto end;
+ }
mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
- mdss_dsi_buf_init(tp);
- mdss_dsi_cmd_dma_add(tp, cmds);
-
/* transmit read comamnd to client */
- mdss_dsi_cmd_dma_tx(ctrl, tp);
+ ret = mdss_dsi_cmd_dma_tx(ctrl, tp);
+ if (IS_ERR_VALUE(ret)) {
+ mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM);
+ pr_err("%s: failed to call\n",
+ __func__);
+ rp->len = 0;
+ goto end;
+ }
/*
* once cmd_dma_done interrupt received,
* return data from client is ready and stored
@@ -1378,7 +1418,7 @@
switch (cmd) {
case DTYPE_ACK_ERR_RESP:
pr_debug("%s: rx ACK_ERR_PACLAGE\n", __func__);
- break;
+ rp->len = 0;
case DTYPE_GEN_READ1_RESP:
case DTYPE_DCS_READ1_RESP:
mdss_dsi_short_read1_resp(rp);
@@ -1394,10 +1434,10 @@
rp->len -= diff; /* align bytes */
break;
default:
- pr_debug("%s: Unknown cmd received\n", __func__);
- break;
+ pr_warning("%s:Invalid response cmd\n", __func__);
+ rp->len = 0;
}
-
+end:
if (left_ctrl_restore)
MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
left_dsi_ctrl); /*restore */
@@ -1413,7 +1453,7 @@
static int mdss_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl,
struct dsi_buf *tp)
{
- int len;
+ int len, ret = 0;
int domain = MDSS_IOMMU_DOMAIN_UNSECURE;
char *bp;
unsigned long size, addr;
@@ -1458,16 +1498,18 @@
MIPI_OUTP((ctrl->ctrl_base) + 0x090, 0x01); /* trigger */
wmb();
- if (!wait_for_completion_timeout(&ctrl->dma_comp,
- msecs_to_jiffies(DMA_TX_TIMEOUT))) {
- pr_err("%s: dma timeout error\n", __func__);
- }
+ ret = wait_for_completion_timeout(&ctrl->dma_comp,
+ msecs_to_jiffies(DMA_TX_TIMEOUT));
+ if (ret == 0)
+ ret = -ETIMEDOUT;
+ else
+ ret = tp->len;
if (is_mdss_iommu_attached())
msm_iommu_unmap_contig_buffer(addr,
mdss_get_iommu_domain(domain), 0, size);
- return tp->len;
+ return ret;
}
static int mdss_dsi_cmd_dma_rx(struct mdss_dsi_ctrl_pdata *ctrl,
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index ac87cbd..94fced0 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -274,8 +274,8 @@
{
struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
- if (mfd->ref_cnt > 1)
- mfd->ref_cnt = 1;
+ for (; mfd->ref_cnt > 1; mfd->ref_cnt--)
+ pm_runtime_put(mfd->fbi->dev);
mdss_fb_release(mfd->fbi, 0);
}
@@ -1096,7 +1096,8 @@
mfd->op_enable);
if (result) {
pm_runtime_put(info->dev);
- pr_err("mdss_fb_open: can't turn on display!\n");
+ pr_err("can't turn on fb%d! rc=%d\n", mfd->index,
+ result);
return result;
}
}
@@ -1122,8 +1123,7 @@
ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info,
mfd->op_enable);
if (ret) {
- pr_err("can't turn off display attached to fb%d!\n",
- mfd->index);
+ pr_err("can't turn off fb%d! rc=%d\n", mfd->index, ret);
return ret;
}
}
diff --git a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
index bcd5f28..367c918 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
@@ -14,6 +14,7 @@
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/stat.h>
#include "mdss_hdmi_hdcp.h"
@@ -1171,6 +1172,38 @@
return rc;
} /* hdmi_hdcp_isr */
+static ssize_t hdmi_hdcp_sysfs_rda_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret;
+ struct hdmi_hdcp_ctrl *hdcp_ctrl =
+ hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_HDCP);
+
+ if (!hdcp_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(hdcp_ctrl->init_data.mutex);
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", hdcp_ctrl->hdcp_state);
+ DEV_DBG("%s: '%d'\n", __func__, hdcp_ctrl->hdcp_state);
+ mutex_unlock(hdcp_ctrl->init_data.mutex);
+
+ return ret;
+} /* hdmi_hdcp_sysfs_rda_hdcp*/
+
+static DEVICE_ATTR(status, S_IRUGO, hdmi_hdcp_sysfs_rda_status, NULL);
+
+static struct attribute *hdmi_hdcp_fs_attrs[] = {
+ &dev_attr_status.attr,
+ NULL,
+};
+
+static struct attribute_group hdmi_hdcp_fs_attr_group = {
+ .name = "hdcp",
+ .attrs = hdmi_hdcp_fs_attrs,
+};
+
void hdmi_hdcp_deinit(void *input)
{
struct hdmi_hdcp_ctrl *hdcp_ctrl = (struct hdmi_hdcp_ctrl *)input;
@@ -1180,6 +1213,9 @@
return;
}
+ sysfs_remove_group(hdcp_ctrl->init_data.sysfs_kobj,
+ &hdmi_hdcp_fs_attr_group);
+
kfree(hdcp_ctrl);
} /* hdmi_hdcp_deinit */
@@ -1203,6 +1239,12 @@
hdcp_ctrl->init_data = *init_data;
+ if (sysfs_create_group(init_data->sysfs_kobj,
+ &hdmi_hdcp_fs_attr_group)) {
+ DEV_ERR("%s: hdcp sysfs group creation failed\n", __func__);
+ goto error;
+ }
+
INIT_DELAYED_WORK(&hdcp_ctrl->hdcp_auth_work, hdmi_hdcp_auth_work);
INIT_WORK(&hdcp_ctrl->hdcp_int_work, hdmi_hdcp_int_work);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_hdcp.h b/drivers/video/msm/mdss/mdss_hdmi_hdcp.h
index d35b2a9..2f0c3b9 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_hdcp.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_hdcp.h
@@ -26,6 +26,7 @@
struct dss_io_data *core_io;
struct dss_io_data *qfprom_io;
struct mutex *mutex;
+ struct kobject *sysfs_kobj;
struct workqueue_struct *workq;
void *cb_data;
void (*notify_status)(void *cb_data, enum hdmi_hdcp_state status);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 1fef395..ad134a0 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -193,12 +193,18 @@
{20480, 247500} } },
};
-static bool is_cea_format(int mode)
+static bool hdmi_tx_is_cea_format(int mode)
{
- if ((mode > 0) && (mode < HDMI_EVFRMT_END))
- return true;
+ bool cea_fmt;
+
+ if ((mode > 0) && (mode <= HDMI_EVFRMT_END))
+ cea_fmt = true;
else
- return false;
+ cea_fmt = false;
+
+ DEV_DBG("%s: %s\n", __func__, cea_fmt ? "Yes" : "No");
+
+ return cea_fmt;
}
const char *hdmi_tx_pm_name(enum hdmi_tx_power_module_type module)
@@ -740,6 +746,7 @@
hdcp_init_data.qfprom_io =
&hdmi_ctrl->pdata.io[HDMI_TX_QFPROM_IO];
hdcp_init_data.mutex = &hdmi_ctrl->mutex;
+ hdcp_init_data.sysfs_kobj = hdmi_ctrl->kobj;
hdcp_init_data.ddc_ctrl = &hdmi_ctrl->ddc_ctrl;
hdcp_init_data.workq = hdmi_ctrl->workq;
hdcp_init_data.notify_status = hdmi_tx_hdcp_cb;
@@ -2210,7 +2217,7 @@
}
if (!hdmi_tx_is_dvi_mode(hdmi_ctrl) &&
- is_cea_format(hdmi_ctrl->video_resolution)) {
+ hdmi_tx_is_cea_format(hdmi_ctrl->video_resolution)) {
rc = hdmi_tx_audio_setup(hdmi_ctrl);
if (rc) {
DEV_ERR("%s: hdmi_msm_audio_setup failed. rc=%d\n",
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 6f9c98e..0a41ef8 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -133,7 +133,6 @@
struct mdss_hw *mdss_irq_handlers[MDSS_MAX_HW_BLK];
static void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on);
-static inline int mdss_mdp_suspend_sub(struct mdss_data_type *mdata);
static int mdss_mdp_parse_dt(struct platform_device *pdev);
static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev);
static int mdss_mdp_parse_dt_mixer(struct platform_device *pdev);
@@ -911,18 +910,6 @@
}
}
-static void mdss_mdp_shutdown(struct platform_device *pdev)
-{
- struct mdss_data_type *mdata = platform_get_drvdata(pdev);
-
- if (!mdata)
- return;
-
- pr_debug("display shutdown\n");
-
- mdss_mdp_suspend_sub(mdata);
-}
-
static int mdss_mdp_probe(struct platform_device *pdev)
{
struct resource *res;
@@ -1795,7 +1782,7 @@
.remove = mdss_mdp_remove,
.suspend = mdss_mdp_suspend,
.resume = mdss_mdp_resume,
- .shutdown = mdss_mdp_shutdown,
+ .shutdown = NULL,
.driver = {
/*
* Driver name must match the device name added in
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index b5a5383..d1595b3 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -24,7 +24,10 @@
#define MDSS_MDP_BUS_FACTOR_SHIFT 10
/* 1.5 bus fudge factor */
#define MDSS_MDP_BUS_FUDGE_FACTOR_IB(val) (((val) / 2) * 3)
+#define MDSS_MDP_BUS_FUDGE_FACTOR_HIGH_IB(val) (val << 1)
#define MDSS_MDP_BUS_FUDGE_FACTOR_AB(val) (val << 1)
+#define MDSS_MDP_BUS_FLOOR_BW (3200000000ULL >> MDSS_MDP_BUS_FACTOR_SHIFT)
+
/* 1.25 clock fudge factor */
#define MDSS_MDP_CLK_FUDGE_FACTOR(val) (((val) * 5) / 4)
@@ -58,6 +61,74 @@
pinfo->clk_rate;
}
+static u32 __mdss_mdp_ctrl_perf_ovrd_helper(struct mdss_mdp_mixer *mixer,
+ u32 *npipe)
+{
+ struct mdss_panel_info *pinfo;
+ struct mdss_mdp_pipe *pipe;
+ u32 mnum, ovrd = 0;
+
+ if (!mixer || !mixer->ctl->panel_data)
+ return 0;
+
+ pinfo = &mixer->ctl->panel_data->panel_info;
+ for (mnum = 0; mnum < MDSS_MDP_MAX_STAGE; mnum++) {
+ pipe = mixer->stage_pipe[mnum];
+ if (pipe && pinfo) {
+ *npipe = *npipe + 1;
+ if ((pipe->src.w >= pipe->src.h) &&
+ (pipe->src.w >= pinfo->xres))
+ ovrd = 1;
+ }
+ }
+
+ return ovrd;
+}
+
+/**
+ * mdss_mdp_ctrl_perf_ovrd() - Determines if performance override is needed
+ * @mdata: Struct containing references to all MDP5 hardware structures
+ * and status info such as interupts, target caps etc.
+ * @ab_quota: Arbitrated bandwidth quota
+ * @ib_quota: Instantaneous bandwidth quota
+ *
+ * Function calculates the minimum required MDP and BIMC clocks to avoid MDP
+ * underflow during portrait video playback. The calculations are based on the
+ * way MDP fetches (bandwidth requirement) and processes data through
+ * MDP pipeline (MDP clock requirement) based on frame size and scaling
+ * requirements.
+ */
+static void __mdss_mdp_ctrl_perf_ovrd(struct mdss_data_type *mdata,
+ u64 *ab_quota, u64 *ib_quota)
+{
+ struct mdss_mdp_ctl *ctl;
+ u32 i, npipe = 0, ovrd = 0;
+
+ for (i = 0; i < mdata->nctl; i++) {
+ ctl = mdata->ctl_off + i;
+ if (!ctl->power_on)
+ continue;
+ ovrd |= __mdss_mdp_ctrl_perf_ovrd_helper(
+ ctl->mixer_left, &npipe);
+ ovrd |= __mdss_mdp_ctrl_perf_ovrd_helper(
+ ctl->mixer_right, &npipe);
+ }
+
+ *ab_quota = MDSS_MDP_BUS_FUDGE_FACTOR_AB(*ab_quota);
+ if (npipe > 1)
+ *ib_quota = MDSS_MDP_BUS_FUDGE_FACTOR_HIGH_IB(*ib_quota);
+ else
+ *ib_quota = MDSS_MDP_BUS_FUDGE_FACTOR_IB(*ib_quota);
+
+ if (ovrd && (*ib_quota < MDSS_MDP_BUS_FLOOR_BW)) {
+ *ib_quota = MDSS_MDP_BUS_FLOOR_BW;
+ pr_debug("forcing the BIMC clock to 200 MHz : %llu bytes",
+ *ib_quota);
+ } else {
+ pr_debug("ib quota : %llu bytes", *ib_quota);
+ }
+}
+
static int mdss_mdp_ctl_perf_commit(struct mdss_data_type *mdata, u32 flags)
{
struct mdss_mdp_ctl *ctl;
@@ -82,16 +153,15 @@
}
}
if (flags & MDSS_MDP_PERF_UPDATE_BUS) {
- bus_ab_quota = bus_ib_quota << MDSS_MDP_BUS_FACTOR_SHIFT;
- bus_ab_quota = MDSS_MDP_BUS_FUDGE_FACTOR_AB(bus_ab_quota);
- bus_ib_quota = MDSS_MDP_BUS_FUDGE_FACTOR_IB(bus_ib_quota);
+ bus_ab_quota = bus_ib_quota;
+ __mdss_mdp_ctrl_perf_ovrd(mdata, &bus_ab_quota, &bus_ib_quota);
bus_ib_quota <<= MDSS_MDP_BUS_FACTOR_SHIFT;
-
+ bus_ab_quota <<= MDSS_MDP_BUS_FACTOR_SHIFT;
mdss_mdp_bus_scale_set_quota(bus_ab_quota, bus_ib_quota);
}
if (flags & MDSS_MDP_PERF_UPDATE_CLK) {
clk_rate = MDSS_MDP_CLK_FUDGE_FACTOR(clk_rate);
- pr_debug("update clk rate = %lu\n", clk_rate);
+ pr_debug("update clk rate = %lu HZ\n", clk_rate);
mdss_mdp_set_clk_rate(clk_rate);
}
mutex_unlock(&mdss_mdp_ctl_lock);
@@ -1337,7 +1407,7 @@
* writeback block
*/
head[len] = head[len - 1];
- head[len].num = -1;
+ head[len].num = head[len - 1].num;
}
mdata->ctl_off = head;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 9b81633..6fb8883 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -409,11 +409,9 @@
if (ctx->polling_en) {
rc = mdss_mdp_video_pollwait(ctl);
} else {
- rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
+ rc = wait_for_completion_timeout(&ctx->vsync_comp,
usecs_to_jiffies(VSYNC_TIMEOUT_US));
- if (rc < 0) {
- pr_warn("vsync wait interrupted ctl=%d\n", ctl->num);
- } else if (rc == 0) {
+ if (rc == 0) {
pr_warn("vsync wait timeout %d, fallback to poll mode\n",
ctl->num);
ctx->polling_en++;
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 4032b91..c4dee86 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -595,7 +595,8 @@
mutex_lock(&mfd->lock);
if (pipe->play_cnt == 0) {
pr_debug("failed for pipe %d\n", pipe->num);
- list_del(&pipe->used_list);
+ if (!list_empty(&pipe->used_list))
+ list_del_init(&pipe->used_list);
mdss_mdp_pipe_destroy(pipe);
}
@@ -827,20 +828,17 @@
pipe->params_changed++;
buf = &pipe->front_buf;
} else if (!pipe->params_changed) {
- if (pipe->mixer) {
- if (!mdss_mdp_pipe_is_staged(pipe)) {
- list_del(&pipe->used_list);
- list_add(&pipe->cleanup_list,
- &mdp5_data->pipes_cleanup);
- }
+ if (pipe->mixer && !mdss_mdp_pipe_is_staged(pipe) &&
+ !list_empty(&pipe->used_list)) {
+ list_del_init(&pipe->used_list);
+ list_add(&pipe->cleanup_list,
+ &mdp5_data->pipes_cleanup);
}
continue;
} else if (pipe->front_buf.num_planes) {
buf = &pipe->front_buf;
} else {
- pr_warn("pipe queue w/o buffer. unstaging layer\n");
- pipe->params_changed = 0;
- mdss_mdp_mixer_pipe_unstage(pipe);
+ pr_warn("pipe queue w/o buffer\n");
continue;
}
@@ -894,9 +892,11 @@
continue;
}
mutex_lock(&mfd->lock);
- list_del(&pipe->used_list);
- list_add(&pipe->cleanup_list,
- &mdp5_data->pipes_cleanup);
+ if (!list_empty(&pipe->used_list)) {
+ list_del_init(&pipe->used_list);
+ list_add(&pipe->cleanup_list,
+ &mdp5_data->pipes_cleanup);
+ }
mutex_unlock(&mfd->lock);
mdss_mdp_mixer_pipe_unstage(pipe);
mdss_mdp_pipe_unmap(pipe);
diff --git a/drivers/video/msm/mdss/mhl_msc.c b/drivers/video/msm/mdss/mhl_msc.c
index d0f93cf..e7cd1be 100644
--- a/drivers/video/msm/mdss/mhl_msc.c
+++ b/drivers/video/msm/mdss/mhl_msc.c
@@ -74,6 +74,22 @@
}
}
+static bool mhl_qualify_path_enable(struct mhl_tx_ctrl *mhl_ctrl)
+{
+ int rc = false;
+
+ if (!mhl_ctrl)
+ return rc;
+
+ if (mhl_ctrl->tmds_en_state ||
+ /* Identify sink with non-standard INT STAT SIZE */
+ (mhl_ctrl->devcap[DEVCAP_OFFSET_MHL_VERSION] == 0x10 &&
+ mhl_ctrl->devcap[DEVCAP_OFFSET_INT_STAT_SIZE] == 0x44))
+ rc = true;
+
+ return rc;
+}
+
void mhl_register_msc(struct mhl_tx_ctrl *ctrl)
{
if (ctrl)
@@ -253,6 +269,11 @@
mhl_tmds_ctrl(mhl_ctrl, TMDS_ENABLE);
mhl_drive_hpd(mhl_ctrl, HPD_UP);
break;
+ case DEVCAP_OFFSET_MHL_VERSION:
+ case DEVCAP_OFFSET_INT_STAT_SIZE:
+ if (mhl_qualify_path_enable(mhl_ctrl))
+ mhl_tmds_ctrl(mhl_ctrl, TMDS_ENABLE);
+ break;
}
break;
case MHL_WRITE_BURST:
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index add15a4..c66d50d 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -794,10 +794,14 @@
void mhl_tmds_ctrl(struct mhl_tx_ctrl *mhl_ctrl, uint8_t on)
{
struct i2c_client *client = mhl_ctrl->i2c_handle;
- if (on)
+
+ if (on) {
MHL_SII_REG_NAME_MOD(REG_TMDS_CCTRL, BIT4, BIT4);
- else
+ mhl_ctrl->tmds_en_state = true;
+ } else {
MHL_SII_REG_NAME_MOD(REG_TMDS_CCTRL, BIT4, 0x00);
+ mhl_ctrl->tmds_en_state = false;
+ }
}
void mhl_drive_hpd(struct mhl_tx_ctrl *mhl_ctrl, uint8_t to_state)
diff --git a/include/linux/cm36283.h b/include/linux/cm36283.h
new file mode 100644
index 0000000..cccd5ee
--- /dev/null
+++ b/include/linux/cm36283.h
@@ -0,0 +1,121 @@
+/* include/linux/cm36283.h
+ *
+ * Copyright (C) 2012 Capella Microsystems Inc.
+ * Author: Frank Hsieh <pengyueh@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __LINUX_CM36283_H
+#define __LINUX_CM36283_H
+
+#define CM36283_I2C_NAME "cm36283"
+
+/* Define Slave Address*/
+#define CM36283_slave_add 0xC0>>1
+
+#define ALS_CALIBRATED 0x6E9F
+#define PS_CALIBRATED 0x509F
+
+/*Define Command Code*/
+#define ALS_CONF 0x00
+#define ALS_THDH 0x01
+#define ALS_THDL 0x02
+#define PS_CONF1 0x03
+#define PS_CONF3 0x04
+#define PS_CANC 0x05
+#define PS_THD 0x06
+#define RESERVED 0x07
+
+#define PS_DATA 0x08
+#define ALS_DATA 0x09
+#define RESERVED2 0x0A
+#define INT_FLAG 0x0B
+#define ID_REG 0x0C
+
+/*cm36283*/
+/*for ALS CONF command*/
+#define CM36283_ALS_IT_80ms (0 << 6)
+#define CM36283_ALS_IT_160ms (1 << 6)
+#define CM36283_ALS_IT_320ms (2 << 6)
+#define CM36283_ALS_IT_640ms (3 << 6)
+#define CM36283_ALS_GAIN_1 (0 << 2)
+#define CM36283_ALS_GAIN_2 (1 << 2)
+#define CM36283_ALS_GAIN_4 (2 << 2)
+#define CM36283_ALS_GAIN_8 (3 << 2)
+#define CM36283_ALS_INT_EN (1 << 1) /*enable/disable Interrupt*/
+#define CM36283_ALS_INT_MASK 0xFFFD
+#define CM36283_ALS_SD (1 << 0) /*enable/disable ALS func, 1:disable , 0: enable*/
+#define CM36283_ALS_SD_MASK 0xFFFE
+
+/*for PS CONF1 command*/
+#define CM36283_PS_ITB_1_2 (0 << 14)
+#define CM36283_PS_ITB_1 (1 << 14)
+#define CM36283_PS_ITB_2 (2 << 14)
+#define CM36283_PS_ITB_4 (3 << 14)
+#define CM36283_PS_INT_OFF (0 << 8) /*enable/disable Interrupt*/
+#define CM36283_PS_INT_IN (1 << 8)
+#define CM36283_PS_INT_OUT (2 << 8)
+#define CM36283_PS_INT_IN_AND_OUT (3 << 8)
+
+#define CM36283_PS_INT_MASK 0xFCFF
+
+#define CM36283_PS_DR_1_40 (0 << 6)
+#define CM36283_PS_DR_1_80 (1 << 6)
+#define CM36283_PS_DR_1_160 (2 << 6)
+#define CM36283_PS_DR_1_320 (3 << 6)
+#define CM36283_PS_IT_1T (0 << 4)
+#define CM36283_PS_IT_1_3T (1 << 4)
+#define CM36283_PS_IT_1_6T (2 << 4)
+#define CM36283_PS_IT_2T (3 << 4)
+#define CM36283_PS_PERS_1 (0 << 2)
+#define CM36283_PS_PERS_2 (1 << 2)
+#define CM36283_PS_PERS_3 (2 << 2)
+#define CM36283_PS_PERS_4 (3 << 2)
+#define CM36283_PS_RES_1 (1 << 1)
+#define CM36283_PS_SD (1 << 0)/*enable/disable PS func, 1:disable , 0: enable*/
+#define CM36283_PS_SD_MASK 0xFFFE
+
+/*for PS CONF3 command*/
+#define CM36283_PS_MS_NORMAL (0 << 14)
+#define CM36283_PS_MS_LOGIC_ENABLE (1 << 14)
+#define CM36283_PS_PROL_63 (0 << 12)
+#define CM36283_PS_PROL_127 (1 << 12)
+#define CM36283_PS_PROL_191 (2 << 12)
+#define CM36283_PS_PROL_255 (3 << 12)
+#define CM36283_PS_SMART_PERS_ENABLE (1 << 4)
+#define CM36283_PS_ACTIVE_FORCE_MODE (1 << 3)
+#define CM36283_PS_ACTIVE_FORCE_TRIG (1 << 2)
+
+/*for INT FLAG*/
+#define INT_FLAG_PS_SPFLAG (1<<14)
+#define INT_FLAG_ALS_IF_L (1<<13)
+#define INT_FLAG_ALS_IF_H (1<<12)
+#define INT_FLAG_PS_IF_CLOSE (1<<9)
+#define INT_FLAG_PS_IF_AWAY (1<<8)
+
+extern unsigned int ps_kparam1;
+extern unsigned int ps_kparam2;
+
+struct cm36283_platform_data {
+ int intr;
+ uint16_t levels[10];
+ uint16_t golden_adc;
+ int (*power)(int, uint8_t); /* power to the chip */
+ uint8_t slave_addr;
+ uint8_t ps_close_thd_set;
+ uint8_t ps_away_thd_set;
+ uint16_t ls_cmd;
+ uint16_t ps_conf1_val;
+ uint16_t ps_conf3_val;
+};
+
+#endif
diff --git a/include/linux/input/synaptics_dsx.h b/include/linux/input/synaptics_dsx.h
index d121695..73016d6 100644
--- a/include/linux/input/synaptics_dsx.h
+++ b/include/linux/input/synaptics_dsx.h
@@ -35,11 +35,8 @@
* struct synaptics_rmi4_platform_data - rmi4 platform data
* @x_flip: x flip flag
* @y_flip: y flip flag
- * @i2c_pull_up: pull up i2c bus with regulator
- * @power_down_enable: enable complete regulator shutdown in suspend
* @irq_gpio: attention interrupt gpio
* @irq_flags: flags used by the irq
- * @reset_flags: flags used by reset line
* @reset_gpio: reset gpio
* @panel_x: panel maximum values on the x
* @panel_y: panel maximum values on the y
@@ -50,7 +47,6 @@
bool x_flip;
bool y_flip;
bool i2c_pull_up;
- bool power_down_enable;
unsigned irq_gpio;
u32 irq_flags;
u32 reset_flags;
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index f0a54eb..d1ee11c 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -149,6 +149,7 @@
uint16_t devcap_state;
uint8_t status[2];
uint8_t path_en_state;
+ uint8_t tmds_en_state;
void *hdmi_mhl_ops;
struct work_struct mhl_msc_send_work;
struct list_head list_cmd;
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 87047d2..f74fcbe 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -20,7 +20,10 @@
#define KGSL_CONTEXT_TRASH_STATE 0x00000020
#define KGSL_CONTEXT_PER_CONTEXT_TS 0x00000040
#define KGSL_CONTEXT_USER_GENERATED_TS 0x00000080
+#define KGSL_CONTEXT_END_OF_FRAME 0x00000100
+
#define KGSL_CONTEXT_NO_FAULT_TOLERANCE 0x00000200
+#define KGSL_CONTEXT_SYNC 0x00000400
/* bits [12:15] are reserved for future use */
#define KGSL_CONTEXT_TYPE_MASK 0x01F00000
#define KGSL_CONTEXT_TYPE_SHIFT 20
@@ -283,7 +286,7 @@
#define IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID \
_IOW(KGSL_IOC_TYPE, 0x7, struct kgsl_device_waittimestamp_ctxtid)
-/* issue indirect commands to the GPU.
+/* DEPRECATED: issue indirect commands to the GPU.
* drawctxt_id must have been created with IOCTL_KGSL_DRAWCTXT_CREATE
* ibaddr and sizedwords must specify a subset of a buffer created
* with IOCTL_KGSL_SHAREDMEM_FROM_PMEM
@@ -291,6 +294,9 @@
* timestamp is a returned counter value which can be passed to
* other ioctls to determine when the commands have been executed by
* the GPU.
+ *
+ * This fucntion is deprecated - consider using IOCTL_KGSL_SUBMIT_COMMANDS
+ * instead
*/
struct kgsl_ringbuffer_issueibcmds {
unsigned int drawctxt_id;
@@ -805,6 +811,77 @@
#define IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK \
_IOWR(KGSL_IOC_TYPE, 0x3C, struct kgsl_gpumem_sync_cache_bulk)
+/*
+ * struct kgsl_cmd_syncpoint_timestamp
+ * @context_id: ID of a KGSL context
+ * @timestamp: GPU timestamp
+ *
+ * This structure defines a syncpoint comprising a context/timestamp pair. A
+ * list of these may be passed by IOCTL_KGSL_SUBMIT_COMMANDS to define
+ * dependencies that must be met before the command can be submitted to the
+ * hardware
+ */
+struct kgsl_cmd_syncpoint_timestamp {
+ unsigned int context_id;
+ unsigned int timestamp;
+};
+
+#define KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP 0
+
+struct kgsl_cmd_syncpoint_fence {
+ int fd;
+};
+
+#define KGSL_CMD_SYNCPOINT_TYPE_FENCE 1
+
+/**
+ * struct kgsl_cmd_syncpoint - Define a sync point for a command batch
+ * @type: type of sync point defined here
+ * @priv: Pointer to the type specific buffer
+ * @size: Size of the type specific buffer
+ *
+ * This structure contains pointers defining a specific command sync point.
+ * The pointer and size should point to a type appropriate structure.
+ */
+struct kgsl_cmd_syncpoint {
+ int type;
+ void __user *priv;
+ unsigned int size;
+};
+
+/**
+ * struct kgsl_submit_commands - Argument to IOCTL_KGSL_SUBMIT_COMMANDS
+ * @context_id: KGSL context ID that owns the commands
+ * @flags:
+ * @cmdlist: User pointer to a list of kgsl_ibdesc structures
+ * @numcmds: Number of commands listed in cmdlist
+ * @synclist: User pointer to a list of kgsl_cmd_syncpoint structures
+ * @numsyncs: Number of sync points listed in synclist
+ * @timestamp: On entry the a user defined timestamp, on exist the timestamp
+ * assigned to the command batch
+ *
+ * This structure specifies a command to send to the GPU hardware. This is
+ * similar to kgsl_issueibcmds expect that it doesn't support the legacy way to
+ * submit IB lists and it adds sync points to block the IB until the
+ * dependencies are satisified. This entry point is the new and preferred way
+ * to submit commands to the GPU.
+ */
+
+struct kgsl_submit_commands {
+ unsigned int context_id;
+ unsigned int flags;
+ struct kgsl_ibdesc __user *cmdlist;
+ unsigned int numcmds;
+ struct kgsl_cmd_syncpoint __user *synclist;
+ unsigned int numsyncs;
+ unsigned int timestamp;
+/* private: reserved for future use */
+ unsigned int __pad[4];
+};
+
+#define IOCTL_KGSL_SUBMIT_COMMANDS \
+ _IOWR(KGSL_IOC_TYPE, 0x3D, struct kgsl_submit_commands)
+
#ifdef __KERNEL__
#ifdef CONFIG_MSM_KGSL_DRM
int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start,
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 041aae7..4f39eaa 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -138,6 +138,16 @@
#define QPNP_ADC_625_UV 625000
#define QPNP_ADC_HWMON_NAME_LENGTH 64
+#define QPNP_MAX_PROP_NAME_LEN 32
+
+/* Structure device for qpnp vadc */
+struct qpnp_vadc_chip;
+
+/* Structure device for qpnp iadc */
+struct qpnp_iadc_chip;
+
+/* Structure device for qpnp adc tm */
+struct qpnp_adc_tm_chip;
/**
* enum qpnp_adc_decimation_type - Sampling rate supported.
@@ -893,7 +903,7 @@
* and returns the physical result
*/
struct qpnp_vadc_scale_fn {
- int32_t (*chan) (int32_t,
+ int32_t (*chan) (struct qpnp_vadc_chip *, int32_t,
const struct qpnp_adc_properties *,
const struct qpnp_vadc_chan_properties *,
struct qpnp_vadc_result *);
@@ -906,7 +916,8 @@
* and returns the physical result
*/
struct qpnp_adc_tm_reverse_scale_fn {
- int32_t (*chan) (struct qpnp_adc_tm_btm_param *,
+ int32_t (*chan) (struct qpnp_vadc_chip *,
+ struct qpnp_adc_tm_btm_param *,
uint32_t *, uint32_t *);
};
@@ -1004,21 +1015,24 @@
|| defined(CONFIG_SENSORS_QPNP_ADC_VOLTAGE_MODULE)
/**
* qpnp_vadc_read() - Performs ADC read on the channel.
+ * @dev: Structure device for qpnp vadc
* @channel: Input channel to perform the ADC read.
* @result: Structure pointer of type adc_chan_result
* in which the ADC read results are stored.
*/
-int32_t qpnp_vadc_read(enum qpnp_vadc_channels channel,
+int32_t qpnp_vadc_read(struct qpnp_vadc_chip *dev,
+ enum qpnp_vadc_channels channel,
struct qpnp_vadc_result *result);
/**
* qpnp_vadc_conv_seq_request() - Performs ADC read on the conversion
* sequencer channel.
+ * @dev: Structure device for qpnp vadc
* @channel: Input channel to perform the ADC read.
* @result: Structure pointer of type adc_chan_result
* in which the ADC read results are stored.
*/
-int32_t qpnp_vadc_conv_seq_request(
+int32_t qpnp_vadc_conv_seq_request(struct qpnp_vadc_chip *dev,
enum qpnp_vadc_trigger trigger_channel,
enum qpnp_vadc_channels channel,
struct qpnp_vadc_result *result);
@@ -1041,6 +1055,7 @@
* qpnp_adc_scale_default() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
* gain and offset.
+ * @dev: Structure device for qpnp vadc
* @adc_code: pre-calibrated digital ouput of the ADC.
* @adc_prop: adc properties of the qpnp adc such as bit resolution,
* reference voltage.
@@ -1048,7 +1063,8 @@
* slope and offset.
* @chan_rslt: Physical result to be stored.
*/
-int32_t qpnp_adc_scale_default(int32_t adc_code,
+int32_t qpnp_adc_scale_default(struct qpnp_vadc_chip *dev,
+ int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
@@ -1057,6 +1073,7 @@
* of an ADC to the ADC reference and compensates for the
* gain and offset. Performs the AMUX out as 2mV/K and returns
* the temperature in milli degC.
+ * @dev: Structure device for qpnp vadc
* @adc_code: pre-calibrated digital ouput of the ADC.
* @adc_prop: adc properties of the qpnp adc such as bit resolution,
* reference voltage.
@@ -1064,7 +1081,8 @@
* slope and offset.
* @chan_rslt: Physical result to be stored.
*/
-int32_t qpnp_adc_scale_pmic_therm(int32_t adc_code,
+int32_t qpnp_adc_scale_pmic_therm(struct qpnp_vadc_chip *dev,
+ int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
@@ -1072,6 +1090,7 @@
* qpnp_adc_scale_batt_therm() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
* gain and offset. Returns the temperature in decidegC.
+ * @dev: Structure device for qpnp vadc
* @adc_code: pre-calibrated digital ouput of the ADC.
* @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
* reference voltage.
@@ -1079,7 +1098,8 @@
* slope and offset.
* @chan_rslt: physical result to be stored.
*/
-int32_t qpnp_adc_scale_batt_therm(int32_t adc_code,
+int32_t qpnp_adc_scale_batt_therm(struct qpnp_vadc_chip *dev,
+ int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
@@ -1087,6 +1107,7 @@
* qpnp_adc_scale_qrd_batt_therm() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
* gain and offset. Returns the temperature in decidegC.
+ * @dev: Structure device for qpnp vadc
* @adc_code: pre-calibrated digital ouput of the ADC.
* @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
* reference voltage.
@@ -1094,7 +1115,8 @@
* slope and offset.
* @chan_rslt: physical result to be stored.
*/
-int32_t qpnp_adc_scale_qrd_batt_therm(int32_t adc_code,
+int32_t qpnp_adc_scale_qrd_batt_therm(struct qpnp_vadc_chip *dev,
+ int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
@@ -1102,6 +1124,7 @@
* qpnp_adc_scale_batt_id() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
* gain and offset.
+ * @dev: Structure device for qpnp vadc
* @adc_code: pre-calibrated digital ouput of the ADC.
* @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
* reference voltage.
@@ -1109,7 +1132,7 @@
* slope and offset.
* @chan_rslt: physical result to be stored.
*/
-int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
+int32_t qpnp_adc_scale_batt_id(struct qpnp_vadc_chip *dev, int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
@@ -1118,6 +1141,7 @@
* of an ADC to the ADC reference and compensates for the
* gain and offset. Returns the temperature of the xo therm in mili
degC.
+ * @dev: Structure device for qpnp vadc
* @adc_code: pre-calibrated digital ouput of the ADC.
* @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
* reference voltage.
@@ -1125,7 +1149,7 @@
* slope and offset.
* @chan_rslt: physical result to be stored.
*/
-int32_t qpnp_adc_tdkntcg_therm(int32_t adc_code,
+int32_t qpnp_adc_tdkntcg_therm(struct qpnp_vadc_chip *dev, int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
@@ -1135,6 +1159,7 @@
* gain and offset. Returns the temperature of the therm in degC.
* It uses a mapping table computed for a 150K pull-up.
* Pull-up1 is an internal pull-up on the AMUX of 150K.
+ * @dev: Structure device for qpnp vadc
* @adc_code: pre-calibrated digital ouput of the ADC.
* @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
* reference voltage.
@@ -1142,7 +1167,7 @@
* slope and offset.
* @chan_rslt: physical result to be stored.
*/
-int32_t qpnp_adc_scale_therm_pu1(int32_t adc_code,
+int32_t qpnp_adc_scale_therm_pu1(struct qpnp_vadc_chip *dev, int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
@@ -1152,6 +1177,7 @@
* gain and offset. Returns the temperature of the therm in degC.
* It uses a mapping table computed for a 100K pull-up.
* Pull-up2 is an internal pull-up on the AMUX of 100K.
+ * @dev: Structure device for qpnp vadc
* @adc_code: pre-calibrated digital ouput of the ADC.
* @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
* reference voltage.
@@ -1159,17 +1185,22 @@
* slope and offset.
* @chan_rslt: physical result to be stored.
*/
-int32_t qpnp_adc_scale_therm_pu2(int32_t adc_code,
+int32_t qpnp_adc_scale_therm_pu2(struct qpnp_vadc_chip *dev, int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
/**
- * qpnp_vadc_is_ready() - Clients can use this API to check if the
- * device is ready to use.
- * @result: 0 on success and -EPROBE_DEFER when probe for the device
- * has not occured.
+ * qpnp_get_vadc() - Clients need to register with the vadc using the
+ * corresponding device instance it wants to read the channels
+ * from. Read the bindings document on how to pass the phandle
+ * for the corresponding vadc driver to register with.
+ * @dev: Clients device structure
+ * @name: Corresponding client's DT parser name. Read the DT bindings
+ * document on how to register with the vadc
+ * @struct qpnp_vadc_chip * - On success returns the vadc device structure
+ * pointer that needs to be used during an ADC request.
*/
-int32_t qpnp_vadc_is_ready(void);
+struct qpnp_vadc_chip *qpnp_get_vadc(struct device *dev, const char *name);
/**
* qpnp_adc_tm_scaler() - Performs reverse calibration.
* @config: Thermal monitoring configuration.
@@ -1185,17 +1216,20 @@
/**
* qpnp_get_vadc_gain_and_offset() - Obtains the VADC gain and offset
* for absolute and ratiometric calibration.
+ * @dev: Structure device for qpnp vadc
* @param: The result in which the ADC offset and gain values are stored.
* @type: The calibration type whether client needs the absolute or
* ratiometric gain and offset values.
*/
-int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_linear_graph *param,
+int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_chip *dev,
+ struct qpnp_vadc_linear_graph *param,
enum qpnp_adc_calib_type calib_type);
/**
* qpnp_adc_scale_millidegc_pmic_voltage_thr() - Performs reverse calibration
* on the low/high temperature threshold values passed by the
* client. The function coverts milldegC to voltage threshold
* and accounts for the corresponding channels scaling as (2mV/K).
+ * @dev: Structure device for qpnp vadc
* @param: The input parameters that contain the low/high temperature
* values.
* @low_threshold: The low threshold value that needs to be updated with
@@ -1203,7 +1237,7 @@
* @high_threshold: The low threshold value that needs to be updated with
* the above calibrated voltage value.
*/
-int32_t qpnp_adc_scale_millidegc_pmic_voltage_thr(
+int32_t qpnp_adc_scale_millidegc_pmic_voltage_thr(struct qpnp_vadc_chip *dev,
struct qpnp_adc_tm_btm_param *param,
uint32_t *low_threshold, uint32_t *high_threshold);
/**
@@ -1211,6 +1245,7 @@
* temperature threshold values passed by the client.
* The function maps the temperature to voltage and applies
* ratiometric calibration on the voltage values.
+ * @dev: Structure device for qpnp vadc
* @param: The input parameters that contain the low/high temperature
* values.
* @low_threshold: The low threshold value that needs to be updated with
@@ -1218,28 +1253,34 @@
* @high_threshold: The low threshold value that needs to be updated with
* the above calibrated voltage value.
*/
-int32_t qpnp_adc_btm_scaler(struct qpnp_adc_tm_btm_param *param,
+int32_t qpnp_adc_btm_scaler(struct qpnp_vadc_chip *dev,
+ struct qpnp_adc_tm_btm_param *param,
uint32_t *low_threshold, uint32_t *high_threshold);
/**
* qpnp_adc_tm_scale_therm_voltage_pu2() - Performs reverse calibration
* and convert given temperature to voltage on supported
* thermistor channels using 100k pull-up.
+ * @dev: Structure device for qpnp vadc
* @param: The input temperature values.
*/
-int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_adc_tm_config *param);
+int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_vadc_chip *dev,
+ struct qpnp_adc_tm_config *param);
/**
* qpnp_adc_tm_scale_therm_voltage_pu2() - Performs reverse calibration
* and converts the given ADC code to temperature for
* thermistor channels using 100k pull-up.
+ * @dev: Structure device for qpnp vadc
* @reg: The input ADC code.
* @result: The physical measurement temperature on the thermistor.
*/
-int32_t qpnp_adc_tm_scale_voltage_therm_pu2(uint32_t reg, int64_t *result);
+int32_t qpnp_adc_tm_scale_voltage_therm_pu2(struct qpnp_vadc_chip *dev,
+ uint32_t reg, int64_t *result);
/**
* qpnp_adc_usb_scaler() - Performs reverse calibration on the low/high
* voltage threshold values passed by the client.
* The function applies ratiometric calibration on the
* voltage values.
+ * @dev: Structure device for qpnp vadc
* @param: The input parameters that contain the low/high voltage
* threshold values.
* @low_threshold: The low threshold value that needs to be updated with
@@ -1247,13 +1288,15 @@
* @high_threshold: The low threshold value that needs to be updated with
* the above calibrated voltage value.
*/
-int32_t qpnp_adc_usb_scaler(struct qpnp_adc_tm_btm_param *param,
+int32_t qpnp_adc_usb_scaler(struct qpnp_vadc_chip *dev,
+ struct qpnp_adc_tm_btm_param *param,
uint32_t *low_threshold, uint32_t *high_threshold);
/**
* qpnp_adc_vbatt_rscaler() - Performs reverse calibration on the low/high
* voltage threshold values passed by the client.
* The function applies ratiometric calibration on the
* voltage values.
+ * @dev: Structure device for qpnp vadc
* @param: The input parameters that contain the low/high voltage
* threshold values.
* @low_threshold: The low threshold value that needs to be updated with
@@ -1261,7 +1304,8 @@
* @high_threshold: The low threshold value that needs to be updated with
* the above calibrated voltage value.
*/
-int32_t qpnp_adc_vbatt_rscaler(struct qpnp_adc_tm_btm_param *param,
+int32_t qpnp_adc_vbatt_rscaler(struct qpnp_vadc_chip *dev,
+ struct qpnp_adc_tm_btm_param *param,
uint32_t *low_threshold, uint32_t *high_threshold);
/**
* qpnp_vadc_iadc_sync_request() - Performs Voltage ADC read and
@@ -1269,107 +1313,127 @@
* voltage and current request the VADC peripheral is
* prepared for conversion and the IADC sync conversion
* is done from the IADC peripheral.
+ * @dev: Structure device for qpnp vadc
* @channel: Input channel to perform the voltage ADC read.
*/
-int32_t qpnp_vadc_iadc_sync_request(enum qpnp_vadc_channels channel);
+int32_t qpnp_vadc_iadc_sync_request(struct qpnp_vadc_chip *dev,
+ enum qpnp_vadc_channels channel);
/**
* qpnp_vadc_iadc_sync_complete_request() - Reads the ADC result and
* unlocks the peripheral.
+ * @dev: Structure device for qpnp vadc
* @result: Structure pointer of type adc_chan_result
* in which the ADC read results are stored.
*/
-int32_t qpnp_vadc_iadc_sync_complete_request(
+int32_t qpnp_vadc_iadc_sync_complete_request(struct qpnp_vadc_chip *dev,
enum qpnp_vadc_channels channel, struct qpnp_vadc_result *result);
/**
* qpnp_vadc_sns_comp_result() - Compensate vbatt readings based on temperature
+ * @dev: Structure device for qpnp vadc
* @result: Voltage in uV that needs compensation.
*/
-int32_t qpnp_vbat_sns_comp_result(int64_t *result);
+int32_t qpnp_vbat_sns_comp_result(struct qpnp_vadc_chip *dev,
+ int64_t *result);
#else
-static inline int32_t qpnp_vadc_read(uint32_t channel,
+static inline int32_t qpnp_vadc_read(struct qpnp_vadc_chip *dev,
+ uint32_t channel,
struct qpnp_vadc_result *result)
{ return -ENXIO; }
-static inline int32_t qpnp_vadc_conv_seq_request(
+static inline int32_t qpnp_vadc_conv_seq_request(struct qpnp_vadc_chip *dev,
enum qpnp_vadc_trigger trigger_channel,
enum qpnp_vadc_channels channel,
struct qpnp_vadc_result *result)
{ return -ENXIO; }
-static inline int32_t qpnp_adc_scale_default(int32_t adc_code,
+static inline int32_t qpnp_adc_scale_default(struct qpnp_vadc_chip *vadc,
+ int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt)
{ return -ENXIO; }
-static inline int32_t qpnp_adc_scale_pmic_therm(int32_t adc_code,
+static inline int32_t qpnp_adc_scale_pmic_therm(struct qpnp_vadc_chip *vadc,
+ int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt)
{ return -ENXIO; }
-static inline int32_t qpnp_adc_scale_batt_therm(int32_t adc_code,
+static inline int32_t qpnp_adc_scale_batt_therm(struct qpnp_vadc_chip *vadc,
+ int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt)
{ return -ENXIO; }
-static inline int32_t qpnp_adc_scale_qrd_batt_therm(int32_t adc_code,
+static inline int32_t qpnp_adc_scale_qrd_batt_therm(
+ struct qpnp_vadc_chip *vadc, int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
{ return -ENXIO; }
-static inline int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
+static inline int32_t qpnp_adc_scale_batt_id(struct qpnp_vadc_chip *vadc,
+ int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt)
{ return -ENXIO; }
-static inline int32_t qpnp_adc_tdkntcg_therm(int32_t adc_code,
+static inline int32_t qpnp_adc_tdkntcg_therm(struct qpnp_vadc_chip *vadc,
+ int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt)
{ return -ENXIO; }
-static inline int32_t qpnp_adc_scale_therm_pu1(int32_t adc_code,
+static inline int32_t qpnp_adc_scale_therm_pu1(struct qpnp_vadc_chip *vadc,
+ int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt)
{ return -ENXIO; }
-static inline int32_t qpnp_adc_scale_therm_pu2(int32_t adc_code,
+static inline int32_t qpnp_adc_scale_therm_pu2(struct qpnp_vadc_chip *vadc,
+ int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt)
{ return -ENXIO; }
-static inline int32_t qpnp_vadc_is_ready(void)
-{ return -ENXIO; }
-static inline int32_t qpnp_get_vadc_gain_and_offset(
+static inline struct qpnp_vadc_chip *qpnp_get_vadc(struct device *dev,
+ const char *name)
+{ return ERR_PTR(-ENXIO); }
+static inline int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_chip *dev,
struct qpnp_vadc_linear_graph *param,
enum qpnp_adc_calib_type calib_type)
{ return -ENXIO; }
-static inline int32_t qpnp_adc_usb_scaler(
+static inline int32_t qpnp_adc_usb_scaler(struct qpnp_vadc_chip *dev,
struct qpnp_adc_tm_btm_param *param,
uint32_t *low_threshold, uint32_t *high_threshold)
{ return -ENXIO; }
-static inline int32_t qpnp_adc_vbatt_rscaler(
+static inline int32_t qpnp_adc_vbatt_rscaler(struct qpnp_vadc_chip *dev,
struct qpnp_adc_tm_btm_param *param,
uint32_t *low_threshold, uint32_t *high_threshold)
{ return -ENXIO; }
-static inline int32_t qpnp_adc_btm_scaler(
+static inline int32_t qpnp_adc_btm_scaler(struct qpnp_vadc_chip *dev,
struct qpnp_adc_tm_btm_param *param,
uint32_t *low_threshold, uint32_t *high_threshold)
{ return -ENXIO; }
static inline int32_t qpnp_adc_scale_millidegc_pmic_voltage_thr(
+ struct qpnp_vadc_chip *dev,
struct qpnp_adc_tm_btm_param *param,
uint32_t *low_threshold, uint32_t *high_threshold)
{ return -ENXIO; }
static inline int32_t qpnp_adc_tm_scale_therm_voltage_pu2(
+ struct qpnp_vadc_chip *dev,
struct qpnp_adc_tm_config *param)
{ return -ENXIO; }
static inline int32_t qpnp_adc_tm_scale_voltage_therm_pu2(
+ struct qpnp_vadc_chip *dev,
uint32_t reg, int64_t *result)
{ return -ENXIO; }
-static inline int32_t qpnp_vadc_iadc_sync_request(
+static inline int32_t qpnp_vadc_iadc_sync_request(struct qpnp_vadc_chip *dev,
enum qpnp_vadc_channels channel)
{ return -ENXIO; }
static inline int32_t qpnp_vadc_iadc_sync_complete_request(
+ struct qpnp_vadc_chip *dev,
enum qpnp_vadc_channels channel,
struct qpnp_vadc_result *result)
{ return -ENXIO; }
-static inline int32_t qpnp_vbat_sns_comp_result(int64_t *result)
+static inline int32_t qpnp_vbat_sns_comp_result(struct qpnp_vadc_chip *dev,
+ int64_t *result)
{ return -ENXIO; }
#endif
@@ -1378,44 +1442,59 @@
|| defined(CONFIG_SENSORS_QPNP_ADC_CURRENT_MODULE)
/**
* qpnp_iadc_read() - Performs ADC read on the current channel.
+ * @dev: Structure device for qpnp iadc
* @channel: Input channel to perform the ADC read.
* @result: Current across rsense in mA.
+ * @return: 0 on success.
*/
-int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
+int32_t qpnp_iadc_read(struct qpnp_iadc_chip *dev,
+ enum qpnp_iadc_channels channel,
struct qpnp_iadc_result *result);
/**
* qpnp_iadc_get_rsense() - Reads the RDS resistance value from the
trim registers.
+ * @dev: Structure device for qpnp iadc
* @rsense: RDS resistance in nOhms.
+ * @return: 0 on success.
*/
-int32_t qpnp_iadc_get_rsense(int32_t *rsense);
+int32_t qpnp_iadc_get_rsense(struct qpnp_iadc_chip *dev, int32_t *rsense);
/**
* qpnp_iadc_get_gain_and_offset() - Performs gain calibration
* over 17.8571mV and offset over selected
* channel. Channel can be internal rsense,
* external rsense and alternate lead pair.
+ * @dev: Structure device for qpnp iadc
* @result: result structure where the gain and offset is stored of
* type qpnp_iadc_calib.
+ * @return: 0 on success.
*/
-int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_calib *result);
+int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_chip *dev,
+ struct qpnp_iadc_calib *result);
/**
- * qpnp_iadc_is_ready() - Clients can use this API to check if the
- * device is ready to use.
- * @result: 0 on success and -EPROBE_DEFER when probe for the device
- * has not occured.
+ * qpnp_get_iadc() - Clients need to register with the iadc with the
+ * corresponding device instance it wants to read the channels.
+ * Read the bindings document on how to pass the phandle for
+ * the corresponding vadc driver to register with.
+ * @dev: Clients device structure
+ * @name: Corresponding client's DT parser name. Read the DT bindings
+ * document on how to register with the iadc
+ * @struct qpnp_iadc_chip * - On success returns the iadc device structure
+ * pointer used everytime client makes an ADC request.
*/
-int32_t qpnp_iadc_is_ready(void);
+struct qpnp_iadc_chip *qpnp_get_iadc(struct device *dev, const char *name);
/**
* qpnp_iadc_vadc_sync_read() - Performs synchronous VADC and IADC read.
* The api is to be used only by the BMS to perform
* simultaneous VADC and IADC measurement for battery voltage
* and current.
+ * @dev: Structure device for qpnp iadc
* @i_channel: Input battery current channel to perform the IADC read.
* @i_result: Current across the rsense in mA.
* @v_channel: Input battery voltage channel to perform VADC read.
* @v_result: Voltage on the vbatt channel with units in mV.
+ * @return: 0 on success.
*/
-int32_t qpnp_iadc_vadc_sync_read(
+int32_t qpnp_iadc_vadc_sync_read(struct qpnp_iadc_chip *dev,
enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result);
/**
@@ -1423,31 +1502,60 @@
* IADC. The offset and gain values are programmed in the trim
* registers. The offset and the gain can be retrieved using
* qpnp_iadc_get_gain_and_offset
+ * @dev: Structure device for qpnp iadc
* @batfet_closed: batfet is opened or closed. The IADC chooses proper
* channel (internal/external) based on batfet status
* for calibration.
* RETURNS: 0 on success.
*/
-int32_t qpnp_iadc_calibrate_for_trim(bool batfet_closed);
-int32_t qpnp_iadc_comp_result(int64_t *result);
+int32_t qpnp_iadc_calibrate_for_trim(struct qpnp_iadc_chip *dev,
+ bool batfet_closed);
+/**
+ * qpnp_iadc_comp_result() - Compensates the result of the current based on
+ * the gain and offset co-effients and rsense parameters.
+ * @dev: Structure device for qpnp iadc
+ * @result: Current value to perform the compensation.
+ * @return: 0 on success.
+ */
+int32_t qpnp_iadc_comp_result(struct qpnp_iadc_chip *dev, int64_t *result);
+/**
+ * qpnp_iadc_skip_calibration() - Clients can use this API to ask the driver
+ * to skip iadc calibrations
+ * @dev: Structure device for qpnp iadc
+ * @result: 0 on success and -EPROBE_DEFER when probe for the device
+ * has not occured.
+ */
+int qpnp_iadc_skip_calibration(struct qpnp_iadc_chip *dev);
+/**
+ * qpnp_iadc_resume_calibration() - Clients can use this API to ask the driver
+ * to resume iadc calibrations
+ * @dev: Structure device for qpnp iadc
+ * @result: 0 on success and -EPROBE_DEFER when probe for the device
+ * has not occured.
+ */
+int qpnp_iadc_resume_calibration(struct qpnp_iadc_chip *dev);
#else
-static inline int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
- struct qpnp_iadc_result *result)
+static inline int32_t qpnp_iadc_read(struct qpnp_iadc_chip *iadc,
+ enum qpnp_iadc_channels channel, struct qpnp_iadc_result *result)
{ return -ENXIO; }
-static inline int32_t qpnp_iadc_get_rsense(int32_t *rsense)
+static inline int32_t qpnp_iadc_get_rsense(struct qpnp_iadc_chip *iadc,
+ int32_t *rsense)
{ return -ENXIO; }
-static inline int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_calib
- *result)
+static inline int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_chip *iadc,
+ struct qpnp_iadc_calib *result)
{ return -ENXIO; }
-static inline int32_t qpnp_iadc_is_ready(void)
-{ return -ENXIO; }
-static inline int32_t qpnp_iadc_vadc_sync_read(
+static inline struct qpnp_iadc_chip *qpnp_get_iadc(struct device *dev,
+ const char *name)
+{ return ERR_PTR(-ENXIO); }
+static inline int32_t qpnp_iadc_vadc_sync_read(struct qpnp_iadc_chip *iadc,
enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result)
{ return -ENXIO; }
-static inline int32_t qpnp_iadc_calibrate_for_trim(bool batfet_closed)
+static inline int32_t qpnp_iadc_calibrate_for_trim(struct qpnp_iadc_chip *iadc,
+ bool batfet_closed)
{ return -ENXIO; }
-static inline int32_t qpnp_iadc_comp_result(int64_t *result, int32_t sign)
+static inline int32_t qpnp_iadc_comp_result(struct qpnp_iadc_chip *iadc,
+ int64_t *result, int32_t sign)
{ return -ENXIO; }
#endif
@@ -1464,14 +1572,15 @@
* Clients pass the low/high voltage along with the threshold
* notification callback.
*/
-int32_t qpnp_adc_tm_usbid_configure(struct qpnp_adc_tm_btm_param *param);
+int32_t qpnp_adc_tm_usbid_configure(struct qpnp_adc_tm_chip *chip,
+ struct qpnp_adc_tm_btm_param *param);
/**
* qpnp_adc_tm_usbid_end() - Disables the monitoring of channel 0 thats
* assigned for monitoring USB_ID. Disables the low/high
* threshold activation for channel 0 as well.
* @param: none.
*/
-int32_t qpnp_adc_tm_usbid_end(void);
+int32_t qpnp_adc_tm_usbid_end(struct qpnp_adc_tm_chip *chip);
/**
* qpnp_adc_tm_channel_measure() - Configures kernel clients a channel to
* monitor the corresponding ADC channel for threshold detection.
@@ -1482,7 +1591,8 @@
* Clients pass the low/high temperature along with the threshold
* notification callback.
*/
-int32_t qpnp_adc_tm_channel_measure(struct qpnp_adc_tm_btm_param *param);
+int32_t qpnp_adc_tm_channel_measure(struct qpnp_adc_tm_chip *chip,
+ struct qpnp_adc_tm_btm_param *param);
/**
* qpnp_adc_tm_disable_chan_meas() - Disables the monitoring of channel thats
* assigned for monitoring kernel clients. Disables the low/high
@@ -1491,45 +1601,36 @@
* This is used to identify the channel for which the corresponding
* channels high/low threshold notification will be disabled.
*/
-int32_t qpnp_adc_tm_disable_chan_meas(struct qpnp_adc_tm_btm_param *param);
+int32_t qpnp_adc_tm_disable_chan_meas(struct qpnp_adc_tm_chip *chip,
+ struct qpnp_adc_tm_btm_param *param);
/**
- * qpnp_adc_tm_is_ready() - Clients can use this API to check if the
- * device is ready to use.
- * @result: 0 on success and -EPROBE_DEFER when probe for the device
- * has not occured.
+ * qpnp_get_adc_tm() - Clients need to register with the adc_tm using the
+ * corresponding device instance it wants to read the channels
+ * from. Read the bindings document on how to pass the phandle
+ * for the corresponding adc_tm driver to register with.
+ * @name: Corresponding client's DT parser name. Read the DT bindings
+ * document on how to register with the vadc
+ * @struct qpnp_adc_tm_chip * - On success returns the vadc device structure
+ * pointer that needs to be used during an ADC TM request.
*/
-int32_t qpnp_adc_tm_is_ready(void);
-/**
- * qpnp_iadc_skip_calibration() - Clients can use this API to ask the driver
- * to skip iadc calibrations
- * @result: 0 on success and -EPROBE_DEFER when probe for the device
- * has not occured.
- */
-int qpnp_iadc_skip_calibration(void);
-/**
- * qpnp_iadc_resume_calibration() - Clients can use this API to ask the driver
- * to resume iadc calibrations
- * @result: 0 on success and -EPROBE_DEFER when probe for the device
- * has not occured.
- */
-int qpnp_iadc_resume_calibration(void);
+struct qpnp_adc_tm_chip *qpnp_get_adc_tm(struct device *dev, const char *name);
#else
static inline int32_t qpnp_adc_tm_usbid_configure(
+ struct qpnp_adc_tm_chip *chip,
struct qpnp_adc_tm_btm_param *param)
{ return -ENXIO; }
-static inline int32_t qpnp_adc_tm_usbid_end(void)
+static inline int32_t qpnp_adc_tm_usbid_end(struct qpnp_adc_tm_chip *chip)
{ return -ENXIO; }
static inline int32_t qpnp_adc_tm_channel_measure(
- struct qpnp_adc_tm_btm_param *param)
+ struct qpnp_adc_tm_chip *chip,
+ struct qpnp_adc_tm_btm_param *param)
{ return -ENXIO; }
-static inline int32_t qpnp_adc_tm_disable_chan_meas(void)
+static inline int32_t qpnp_adc_tm_disable_chan_meas(
+ struct qpnp_adc_tm_chip *chip)
{ return -ENXIO; }
-static inline int32_t qpnp_adc_tm_is_ready(void)
-{ return -ENXIO; }
-static inline int qpnp_iadc_skip_calibration(void)
-{ return -ENXIO; }
-static inline int qpnp_iadc_resume_calibration(void);
-{ return -ENXIO; }
+static inline struct qpnp_adc_tm_chip *qpnp_get_adc_tm(struct device *dev,
+ const char *name)
+{ return ERR_PTR(-ENXIO); }
#endif
#endif
diff --git a/include/linux/stk3x1x.h b/include/linux/stk3x1x.h
new file mode 100644
index 0000000..33625bd
--- /dev/null
+++ b/include/linux/stk3x1x.h
@@ -0,0 +1,28 @@
+/*
+ *
+ * Id: stk3x1x.h
+ *
+ * Copyright (C) 2012 Lex Hsieh <lex_hsieh@sitronix.com.tw>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ */
+#ifndef __STK3X1X_H__
+#define __STK3X1X_H__
+
+/* platform data */
+struct stk3x1x_platform_data {
+ uint8_t state_reg;
+ uint8_t psctrl_reg;
+ uint8_t alsctrl_reg;
+ uint8_t ledctrl_reg;
+ uint8_t wait_reg;
+ uint16_t ps_thd_h;
+ uint16_t ps_thd_l;
+ int int_pin;
+ uint32_t transmittance;
+};
+
+#endif /* __STK3X1X_H__ */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 8d104c6..59b6338 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -314,6 +314,7 @@
* @pclk: clock struct of iface_clk.
* @phy_reset_clk: clock struct of phy_clk.
* @core_clk: clock struct of core_bus_clk.
+ * @sleep_clk: clock struct of sleep_clk for USB PHY.
* @core_clk_rate: core clk max frequency
* @regs: ioremapped register base address.
* @inputs: OTG state machine inputs(Id, SessValid etc).
@@ -350,6 +351,7 @@
struct clk *pclk;
struct clk *phy_reset_clk;
struct clk *core_clk;
+ struct clk *sleep_clk;
long core_clk_rate;
struct resource *io_res;
void __iomem *regs;
@@ -461,11 +463,20 @@
bool l1_supported;
};
+/**
+ * struct msm_hsic_host_platform_data - platform device data
+ * for msm_hsic_host driver.
+ * @phy_sof_workaround: Enable ALL PHY SOF bug related workarounds for
+ SUSPEND, RESET and RESUME.
+ * @phy_susp_sof_workaround: Enable PHY SOF workaround only for SUSPEND.
+ *
+ */
struct msm_hsic_host_platform_data {
unsigned strobe;
unsigned data;
bool ignore_cal_pad_config;
bool phy_sof_workaround;
+ bool phy_susp_sof_workaround;
u32 reset_delay;
int strobe_pad_offset;
int data_pad_offset;
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 4ad1ca9..bd4cddf 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -92,7 +92,7 @@
#define READDONE_IDX_SEQ_ID 10
#define SOFT_PAUSE_PERIOD 30 /* ramp up/down for 30ms */
-#define SOFT_PAUSE_STEP 2000 /* Step value 2ms or 2000us */
+#define SOFT_PAUSE_STEP 0 /* Step value 0ms or 0us */
enum {
SOFT_PAUSE_CURVE_LINEAR = 0,
SOFT_PAUSE_CURVE_EXP,
@@ -100,7 +100,7 @@
};
#define SOFT_VOLUME_PERIOD 30 /* ramp up/down for 30ms */
-#define SOFT_VOLUME_STEP 2000 /* Step value 2ms or 2000us */
+#define SOFT_VOLUME_STEP 0 /* Step value 0ms or 0us */
enum {
SOFT_VOLUME_CURVE_LINEAR = 0,
SOFT_VOLUME_CURVE_EXP,
diff --git a/sound/soc/msm/mdm9625.c b/sound/soc/msm/mdm9625.c
index ad8d85a..60e2c37 100644
--- a/sound/soc/msm/mdm9625.c
+++ b/sound/soc/msm/mdm9625.c
@@ -349,6 +349,14 @@
return 0;
}
+static int mdm9625_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ rate->min = rate->max = 48000;
+ return 0;
+}
static int mdm9625_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -951,6 +959,45 @@
.be_hw_params_fixup = mdm9625_auxpcm_be_params_fixup,
.ops = &mdm9625_auxpcm_be_ops,
},
+ /* Incall Record Uplink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_TX,
+ .stream_name = "Voice Uplink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32772",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ .be_hw_params_fixup = mdm9625_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Downlink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_RX,
+ .stream_name = "Voice Downlink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32771",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ .be_hw_params_fixup = mdm9625_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Music BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE_PLAYBACK_TX,
+ .stream_name = "Voice Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32773",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ .be_hw_params_fixup = mdm9625_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
};
static struct snd_soc_card snd_soc_card_mdm9625 = {
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index d3ba3d5..85ed869 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -1146,6 +1146,22 @@
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA9,
},
+ {
+ .name = "VoLTE",
+ .stream_name = "VoLTE",
+ .cpu_dai_name = "VoLTE",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOLTE,
+ },
/* Backend BT/FM DAI Links */
{
.name = LPASS_BE_INT_BT_SCO_RX,
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 056e2dc..60dd522 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -379,6 +379,21 @@
return false;
}
+static void voc_set_error_state(uint16_t reset_proc)
+{
+ struct voice_data *v = NULL;
+ int i;
+
+ for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+ if (reset_proc == APR_DEST_MODEM && i == VOC_PATH_FULL)
+ continue;
+
+ v = &common.voice[i];
+ if (v != NULL)
+ v->voc_state = VOC_ERROR;
+ }
+}
+
static bool is_other_session_active(u32 session_id)
{
int i;
@@ -4347,7 +4362,7 @@
mutex_lock(&v->lock);
if (v->voc_state == VOC_RUN || v->voc_state == VOC_ERROR ||
- v->voc_state == VOC_STANDBY) {
+ v->voc_state == VOC_CHANGE || v->voc_state == VOC_STANDBY) {
pr_debug("%s: VOC_STATE: %d\n", __func__, v->voc_state);
@@ -4357,7 +4372,13 @@
voice_destroy_mvm_cvs_session(v);
v->voc_state = VOC_RELEASE;
+ } else {
+ pr_err("%s: Error: End voice called in state %d\n",
+ __func__, v->voc_state);
+
+ ret = -EINVAL;
}
+
mutex_unlock(&v->lock);
return ret;
}
@@ -4559,8 +4580,10 @@
}
v->voc_state = VOC_RUN;
- } else if (v->voc_state == VOC_STANDBY) {
- pr_err("Error: start voice in Standby\n");
+ } else {
+ pr_err("%s: Error: Start voice called in state %d\n",
+ __func__, v->voc_state);
+
ret = -EINVAL;
goto fail;
}
@@ -4602,7 +4625,6 @@
struct common_data *c = NULL;
struct voice_data *v = NULL;
int i = 0;
- uint32_t session_id = 0;
if ((data == NULL) || (priv == NULL)) {
pr_err("%s: data or priv is NULL\n", __func__);
@@ -4619,25 +4641,6 @@
if (data->reset_proc == APR_DEST_MODEM) {
pr_debug("%s: Received MODEM reset event\n", __func__);
- session_id = voc_get_session_id(VOICE_SESSION_NAME);
- v = voice_get_session(session_id);
- if (v != NULL)
- v->voc_state = VOC_ERROR;
-
- session_id = voc_get_session_id(VOICE2_SESSION_NAME);
- v = voice_get_session(session_id);
- if (v != NULL)
- v->voc_state = VOC_ERROR;
-
- session_id = voc_get_session_id(VOLTE_SESSION_NAME);
- v = voice_get_session(session_id);
- if (v != NULL)
- v->voc_state = VOC_ERROR;
-
- session_id = voc_get_session_id(QCHAT_SESSION_NAME);
- v = voice_get_session(session_id);
- if (v != NULL)
- v->voc_state = VOC_ERROR;
} else {
pr_debug("%s: Reset event received in Voice service\n",
__func__);
@@ -4655,7 +4658,7 @@
}
/* clean up srvcc rec flag */
c->srvcc_rec_flag = false;
-
+ voc_set_error_state(data->reset_proc);
return 0;
}
@@ -4753,7 +4756,6 @@
struct common_data *c = NULL;
struct voice_data *v = NULL;
int i = 0;
- uint32_t session_id = 0;
if ((data == NULL) || (priv == NULL)) {
pr_err("%s: data or priv is NULL\n", __func__);
@@ -4770,25 +4772,6 @@
if (data->reset_proc == APR_DEST_MODEM) {
pr_debug("%s: Received Modem reset event\n", __func__);
- session_id = voc_get_session_id(VOICE_SESSION_NAME);
- v = voice_get_session(session_id);
- if (v != NULL)
- v->voc_state = VOC_ERROR;
-
- session_id = voc_get_session_id(VOICE2_SESSION_NAME);
- v = voice_get_session(session_id);
- if (v != NULL)
- v->voc_state = VOC_ERROR;
-
- session_id = voc_get_session_id(VOLTE_SESSION_NAME);
- v = voice_get_session(session_id);
- if (v != NULL)
- v->voc_state = VOC_ERROR;
-
- session_id = voc_get_session_id(QCHAT_SESSION_NAME);
- v = voice_get_session(session_id);
- if (v != NULL)
- v->voc_state = VOC_ERROR;
} else {
pr_debug("%s: Reset event received in Voice service\n",
__func__);
@@ -4800,6 +4783,8 @@
for (i = 0; i < MAX_VOC_SESSIONS; i++)
c->voice[i].cvs_handle = 0;
}
+
+ voc_set_error_state(data->reset_proc);
return 0;
}
@@ -5034,7 +5019,6 @@
struct common_data *c = NULL;
struct voice_data *v = NULL;
int i = 0;
- uint32_t session_id = 0;
if ((data == NULL) || (priv == NULL)) {
pr_err("%s: data or priv is NULL\n", __func__);
@@ -5047,25 +5031,6 @@
if (data->reset_proc == APR_DEST_MODEM) {
pr_debug("%s: Received Modem reset event\n", __func__);
- session_id = voc_get_session_id(VOICE_SESSION_NAME);
- v = voice_get_session(session_id);
- if (v != NULL)
- v->voc_state = VOC_ERROR;
-
- session_id = voc_get_session_id(VOICE2_SESSION_NAME);
- v = voice_get_session(session_id);
- if (v != NULL)
- v->voc_state = VOC_ERROR;
-
- session_id = voc_get_session_id(VOLTE_SESSION_NAME);
- v = voice_get_session(session_id);
- if (v != NULL)
- v->voc_state = VOC_ERROR;
-
- session_id = voc_get_session_id(QCHAT_SESSION_NAME);
- v = voice_get_session(session_id);
- if (v != NULL)
- v->voc_state = VOC_ERROR;
} else {
pr_debug("%s: Reset event received in Voice service\n",
__func__);
@@ -5077,6 +5042,8 @@
for (i = 0; i < MAX_VOC_SESSIONS; i++)
c->voice[i].cvp_handle = 0;
}
+
+ voc_set_error_state(data->reset_proc);
return 0;
}