aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/interconnect/qcom,msm8916.yaml77
-rw-r--r--Documentation/devicetree/bindings/nvmem/imx-ocotp.txt3
-rw-r--r--Documentation/devicetree/bindings/nvmem/qcom,spmi-sdam.yaml84
-rw-r--r--Documentation/devicetree/bindings/slimbus/bus.txt10
-rw-r--r--Documentation/devicetree/bindings/soundwire/qcom,sdw.txt167
-rw-r--r--Documentation/devicetree/bindings/soundwire/soundwire-controller.yaml2
-rw-r--r--Documentation/driver-api/interconnect.rst22
-rw-r--r--drivers/android/binder.c37
-rw-r--r--drivers/bus/fsl-mc/fsl-mc-bus.c6
-rw-r--r--drivers/char/hpet.c2
-rw-r--r--drivers/extcon/extcon-arizona.c354
-rw-r--r--drivers/extcon/extcon-sm5502.c10
-rw-r--r--drivers/firmware/google/coreboot_table.c7
-rw-r--r--drivers/firmware/google/gsmi.c25
-rw-r--r--drivers/firmware/stratix10-svc.c4
-rw-r--r--drivers/fpga/dfl-afu-main.c2
-rw-r--r--drivers/fpga/dfl-fme-main.c2
-rw-r--r--drivers/fpga/ts73xx-fpga.c4
-rw-r--r--drivers/fpga/xilinx-pr-decoupler.c3
-rw-r--r--drivers/interconnect/Makefile1
-rw-r--r--drivers/interconnect/core.c168
-rw-r--r--drivers/interconnect/internal.h42
-rw-r--r--drivers/interconnect/qcom/Kconfig9
-rw-r--r--drivers/interconnect/qcom/Makefile2
-rw-r--r--drivers/interconnect/qcom/msm8916.c554
-rw-r--r--drivers/interconnect/qcom/msm8974.c32
-rw-r--r--drivers/interconnect/qcom/qcs404.c32
-rw-r--r--drivers/interconnect/qcom/sdm845.c16
-rw-r--r--drivers/interconnect/trace.h88
-rw-r--r--drivers/misc/cardreader/alcor_pci.c8
-rw-r--r--drivers/misc/cardreader/rts5261.c11
-rw-r--r--drivers/misc/cxl/context.c2
-rw-r--r--drivers/misc/genwqe/card_ddcb.c8
-rw-r--r--drivers/misc/isl29020.c1
-rw-r--r--drivers/misc/mei/bus.c10
-rw-r--r--drivers/misc/mei/hdcp/mei_hdcp.c33
-rw-r--r--drivers/misc/mei/hw-me-regs.h6
-rw-r--r--drivers/misc/mei/pci-me.c4
-rw-r--r--drivers/misc/mic/card/mic_debugfs.c3
-rw-r--r--drivers/misc/mic/cosm/cosm_debugfs.c3
-rw-r--r--drivers/misc/mic/host/mic_debugfs.c3
-rw-r--r--drivers/misc/pti.c4
-rw-r--r--drivers/misc/pvpanic.c12
-rw-r--r--drivers/misc/sram-exec.c21
-rw-r--r--drivers/misc/ti-st/st_core.c4
-rw-r--r--drivers/misc/tsl2550.c12
-rw-r--r--drivers/misc/xilinx_sdfec.c12
-rw-r--r--drivers/nvmem/Kconfig8
-rw-r--r--drivers/nvmem/Makefile2
-rw-r--r--drivers/nvmem/core.c8
-rw-r--r--drivers/nvmem/imx-ocotp-scu.c16
-rw-r--r--drivers/nvmem/imx-ocotp.c79
-rw-r--r--drivers/nvmem/qcom-spmi-sdam.c192
-rw-r--r--drivers/siox/siox.h2
-rw-r--r--drivers/slimbus/qcom-ctrl.c2
-rw-r--r--drivers/slimbus/qcom-ngd-ctrl.c20
-rw-r--r--drivers/slimbus/slimbus.h2
-rw-r--r--drivers/soundwire/Kconfig9
-rw-r--r--drivers/soundwire/Makefile4
-rw-r--r--drivers/soundwire/bus.c55
-rw-r--r--drivers/soundwire/cadence_master.c66
-rw-r--r--drivers/soundwire/intel.c3
-rw-r--r--drivers/soundwire/qcom.c861
-rw-r--r--drivers/soundwire/stream.c8
-rw-r--r--drivers/uio/uio_dmem_genirq.c6
-rw-r--r--drivers/uio/uio_pdrv_genirq.c2
-rw-r--r--drivers/visorbus/visorchipset.c11
-rw-r--r--drivers/vme/bridges/vme_fake.c30
-rw-r--r--drivers/w1/masters/omap_hdq.c348
-rw-r--r--include/dt-bindings/interconnect/qcom,msm8916.h100
-rw-r--r--include/linux/alcor_pci.h1
-rw-r--r--include/linux/extcon.h30
-rw-r--r--include/linux/interconnect-provider.h14
-rw-r--r--include/linux/soundwire/sdw.h4
-rw-r--r--include/linux/soundwire/sdw_intel.h11
-rw-r--r--include/uapi/misc/pvpanic.h9
76 files changed, 3128 insertions, 697 deletions
diff --git a/Documentation/devicetree/bindings/interconnect/qcom,msm8916.yaml b/Documentation/devicetree/bindings/interconnect/qcom,msm8916.yaml
new file mode 100644
index 000000000000..4107e60cab12
--- /dev/null
+++ b/Documentation/devicetree/bindings/interconnect/qcom,msm8916.yaml
@@ -0,0 +1,77 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interconnect/qcom,msm8916.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm MSM8916 Network-On-Chip interconnect
+
+maintainers:
+ - Georgi Djakov <georgi.djakov@linaro.org>
+
+description: |
+ The Qualcomm MSM8916 interconnect providers support adjusting the
+ bandwidth requirements between the various NoC fabrics.
+
+properties:
+ compatible:
+ enum:
+ - qcom,msm8916-bimc
+ - qcom,msm8916-pcnoc
+ - qcom,msm8916-snoc
+
+ reg:
+ maxItems: 1
+
+ '#interconnect-cells':
+ const: 1
+
+ clock-names:
+ items:
+ - const: bus
+ - const: bus_a
+
+ clocks:
+ items:
+ - description: Bus Clock
+ - description: Bus A Clock
+
+required:
+ - compatible
+ - reg
+ - '#interconnect-cells'
+ - clock-names
+ - clocks
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,rpmcc.h>
+
+ bimc: interconnect@400000 {
+ compatible = "qcom,msm8916-bimc";
+ reg = <0x00400000 0x62000>;
+ #interconnect-cells = <1>;
+ clock-names = "bus", "bus_a";
+ clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
+ <&rpmcc RPM_SMD_BIMC_A_CLK>;
+ };
+
+ pcnoc: interconnect@500000 {
+ compatible = "qcom,msm8916-pcnoc";
+ reg = <0x00500000 0x11000>;
+ #interconnect-cells = <1>;
+ clock-names = "bus", "bus_a";
+ clocks = <&rpmcc RPM_SMD_PCNOC_CLK>,
+ <&rpmcc RPM_SMD_PCNOC_A_CLK>;
+ };
+
+ snoc: interconnect@580000 {
+ compatible = "qcom,msm8916-snoc";
+ reg = <0x00580000 0x14000>;
+ #interconnect-cells = <1>;
+ clock-names = "bus", "bus_a";
+ clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
+ <&rpmcc RPM_SMD_SNOC_A_CLK>;
+ };
diff --git a/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt b/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt
index 904dadf3d07b..6e346d5cddcf 100644
--- a/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt
+++ b/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt
@@ -2,7 +2,7 @@ Freescale i.MX6 On-Chip OTP Controller (OCOTP) device tree bindings
This binding represents the on-chip eFuse OTP controller found on
i.MX6Q/D, i.MX6DL/S, i.MX6SL, i.MX6SX, i.MX6UL, i.MX6ULL/ULZ, i.MX6SLL,
-i.MX7D/S, i.MX7ULP, i.MX8MQ, i.MX8MM and i.MX8MN SoCs.
+i.MX7D/S, i.MX7ULP, i.MX8MQ, i.MX8MM, i.MX8MN and i.MX8MP SoCs.
Required properties:
- compatible: should be one of
@@ -17,6 +17,7 @@ Required properties:
"fsl,imx8mq-ocotp" (i.MX8MQ),
"fsl,imx8mm-ocotp" (i.MX8MM),
"fsl,imx8mn-ocotp" (i.MX8MN),
+ "fsl,imx8mp-ocotp" (i.MX8MP),
followed by "syscon".
- #address-cells : Should be 1
- #size-cells : Should be 1
diff --git a/Documentation/devicetree/bindings/nvmem/qcom,spmi-sdam.yaml b/Documentation/devicetree/bindings/nvmem/qcom,spmi-sdam.yaml
new file mode 100644
index 000000000000..7bbd4e62044e
--- /dev/null
+++ b/Documentation/devicetree/bindings/nvmem/qcom,spmi-sdam.yaml
@@ -0,0 +1,84 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/nvmem/qcom,spmi-sdam.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Technologies, Inc. SPMI SDAM DT bindings
+
+maintainers:
+ - Shyam Kumar Thella <sthella@codeaurora.org>
+
+description: |
+ The SDAM provides scratch register space for the PMIC clients. This
+ memory can be used by software to store information or communicate
+ to/from the PBUS.
+
+allOf:
+ - $ref: "nvmem.yaml#"
+
+properties:
+ compatible:
+ enum:
+ - qcom,spmi-sdam
+
+ reg:
+ maxItems: 1
+
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 1
+
+ ranges: true
+
+required:
+ - compatible
+ - reg
+ - ranges
+
+patternProperties:
+ "^.*@[0-9a-f]+$":
+ type: object
+
+ properties:
+ reg:
+ maxItems: 1
+ description:
+ Offset and size in bytes within the storage device.
+
+ bits:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ maxItems: 1
+ items:
+ items:
+ - minimum: 0
+ maximum: 7
+ description:
+ Offset in bit within the address range specified by reg.
+ - minimum: 1
+ description:
+ Size in bit within the address range specified by reg.
+
+ required:
+ - reg
+
+ additionalProperties: false
+
+examples:
+ - |
+ sdam_1: nvram@b000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "qcom,spmi-sdam";
+ reg = <0xb000 0x100>;
+ ranges = <0 0xb000 0x100>;
+
+ /* Data cells */
+ restart_reason: restart@50 {
+ reg = <0x50 0x1>;
+ bits = <6 2>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/slimbus/bus.txt b/Documentation/devicetree/bindings/slimbus/bus.txt
index 52fa6426388c..bbe871f82a8b 100644
--- a/Documentation/devicetree/bindings/slimbus/bus.txt
+++ b/Documentation/devicetree/bindings/slimbus/bus.txt
@@ -32,6 +32,10 @@ Required property for SLIMbus child node if it is present:
Product Code, shall be in lower case hexadecimal with leading
zeroes suppressed
+Optional property for SLIMbus child node if it is present:
+- slim-ifc-dev - Should be phandle to SLIMBus Interface device.
+ Required for devices which deal with streams.
+
SLIMbus example for Qualcomm's slimbus manager component:
slim@28080000 {
@@ -43,8 +47,14 @@ SLIMbus example for Qualcomm's slimbus manager component:
#address-cells = <2>;
#size-cell = <0>;
+ codec_ifd: ifd@0,0{
+ compatible = "slim217,60";
+ reg = <0 0>;
+ };
+
codec: wcd9310@1,0{
compatible = "slim217,60";
reg = <1 0>;
+ slim-ifc-dev = <&codec_ifd>;
};
};
diff --git a/Documentation/devicetree/bindings/soundwire/qcom,sdw.txt b/Documentation/devicetree/bindings/soundwire/qcom,sdw.txt
new file mode 100644
index 000000000000..436547f3b155
--- /dev/null
+++ b/Documentation/devicetree/bindings/soundwire/qcom,sdw.txt
@@ -0,0 +1,167 @@
+Qualcomm SoundWire Controller Bindings
+
+
+This binding describes the Qualcomm SoundWire Controller along with its
+board specific bus parameters.
+
+- compatible:
+ Usage: required
+ Value type: <stringlist>
+ Definition: must be "qcom,soundwire-v<MAJOR>.<MINOR>.<STEP>",
+ Example:
+ "qcom,soundwire-v1.3.0"
+ "qcom,soundwire-v1.5.0"
+ "qcom,soundwire-v1.6.0"
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: the base address and size of SoundWire controller
+ address space.
+
+- interrupts:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: should specify the SoundWire Controller IRQ
+
+- clock-names:
+ Usage: required
+ Value type: <stringlist>
+ Definition: should be "iface" for SoundWire Controller interface clock
+
+- clocks:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: should specify the SoundWire Controller interface clock
+
+- #sound-dai-cells:
+ Usage: required
+ Value type: <u32>
+ Definition: must be 1 for digital audio interfaces on the controller.
+
+- qcom,dout-ports:
+ Usage: required
+ Value type: <u32>
+ Definition: must be count of data out ports
+
+- qcom,din-ports:
+ Usage: required
+ Value type: <u32>
+ Definition: must be count of data in ports
+
+- qcom,ports-offset1:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: should specify payload transport window offset1 of each
+ data port. Out ports followed by In ports.
+ More info in MIPI Alliance SoundWire 1.0 Specifications.
+
+- qcom,ports-offset2:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: should specify payload transport window offset2 of each
+ data port. Out ports followed by In ports.
+ More info in MIPI Alliance SoundWire 1.0 Specifications.
+
+- qcom,ports-sinterval-low:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: should be sample interval low of each data port.
+ Out ports followed by In ports. Used for Sample Interval
+ calculation.
+ More info in MIPI Alliance SoundWire 1.0 Specifications.
+
+- qcom,ports-word-length:
+ Usage: optional
+ Value type: <prop-encoded-array>
+ Definition: should be size of payload channel sample.
+ More info in MIPI Alliance SoundWire 1.0 Specifications.
+
+- qcom,ports-block-pack-mode:
+ Usage: optional
+ Value type: <prop-encoded-array>
+ Definition: should be 0 or 1 to indicate the block packing mode.
+ 0 to indicate Blocks are per Channel
+ 1 to indicate Blocks are per Port.
+ Out ports followed by In ports.
+ More info in MIPI Alliance SoundWire 1.0 Specifications.
+
+- qcom,ports-block-group-count:
+ Usage: optional
+ Value type: <prop-encoded-array>
+ Definition: should be in range 1 to 4 to indicate how many sample
+ intervals are combined into a payload.
+ Out ports followed by In ports.
+ More info in MIPI Alliance SoundWire 1.0 Specifications.
+
+- qcom,ports-lane-control:
+ Usage: optional
+ Value type: <prop-encoded-array>
+ Definition: should be in range 0 to 7 to identify which data lane
+ the data port uses.
+ Out ports followed by In ports.
+ More info in MIPI Alliance SoundWire 1.0 Specifications.
+
+- qcom,ports-hstart:
+ Usage: optional
+ Value type: <prop-encoded-array>
+ Definition: should be number identifying lowerst numbered coloum in
+ SoundWire Frame, i.e. left edge of the Transport sub-frame
+ for each port. Values between 0 and 15 are valid.
+ Out ports followed by In ports.
+ More info in MIPI Alliance SoundWire 1.0 Specifications.
+
+- qcom,ports-hstop:
+ Usage: optional
+ Value type: <prop-encoded-array>
+ Definition: should be number identifying highest numbered coloum in
+ SoundWire Frame, i.e. the right edge of the Transport
+ sub-frame for each port. Values between 0 and 15 are valid.
+ Out ports followed by In ports.
+ More info in MIPI Alliance SoundWire 1.0 Specifications.
+
+- qcom,dports-type:
+ Usage: optional
+ Value type: <prop-encoded-array>
+ Definition: should be one of the following types
+ 0 for reduced port
+ 1 for simple ports
+ 2 for full port
+ Out ports followed by In ports.
+ More info in MIPI Alliance SoundWire 1.0 Specifications.
+
+Note:
+ More Information on detail of encoding of these fields can be
+found in MIPI Alliance SoundWire 1.0 Specifications.
+
+= SoundWire devices
+Each subnode of the bus represents SoundWire device attached to it.
+The properties of these nodes are defined by the individual bindings.
+
+= EXAMPLE
+The following example represents a SoundWire controller on DB845c board
+which has controller integrated inside WCD934x codec on SDM845 SoC.
+
+soundwire: soundwire@c85 {
+ compatible = "qcom,soundwire-v1.3.0";
+ reg = <0xc85 0x20>;
+ interrupts = <20 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&wcc>;
+ clock-names = "iface";
+ #sound-dai-cells = <1>;
+ qcom,dports-type = <0>;
+ qcom,dout-ports = <6>;
+ qcom,din-ports = <2>;
+ qcom,ports-sinterval-low = /bits/ 8 <0x07 0x1F 0x3F 0x7 0x1F 0x3F 0x0F 0x0F>;
+ qcom,ports-offset1 = /bits/ 8 <0x01 0x02 0x0C 0x6 0x12 0x0D 0x07 0x0A >;
+ qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x1F 0x00 0x00 0x1F 0x00 0x00>;
+
+ /* Left Speaker */
+ left{
+ ....
+ };
+
+ /* Right Speaker */
+ right{
+ ....
+ };
+};
diff --git a/Documentation/devicetree/bindings/soundwire/soundwire-controller.yaml b/Documentation/devicetree/bindings/soundwire/soundwire-controller.yaml
index 1b43993bccdb..330924b8618e 100644
--- a/Documentation/devicetree/bindings/soundwire/soundwire-controller.yaml
+++ b/Documentation/devicetree/bindings/soundwire/soundwire-controller.yaml
@@ -69,6 +69,7 @@ examples:
reg = <0 1>;
powerdown-gpios = <&wcdpinctrl 2 0>;
#thermal-sensor-cells = <0>;
+ #sound-dai-cells = <0>;
};
speaker@0,2 {
@@ -76,6 +77,7 @@ examples:
reg = <0 2>;
powerdown-gpios = <&wcdpinctrl 2 0>;
#thermal-sensor-cells = <0>;
+ #sound-dai-cells = <0>;
};
};
diff --git a/Documentation/driver-api/interconnect.rst b/Documentation/driver-api/interconnect.rst
index cdeb5825f314..5ed4f57a6bac 100644
--- a/Documentation/driver-api/interconnect.rst
+++ b/Documentation/driver-api/interconnect.rst
@@ -91,3 +91,25 @@ Interconnect consumers are the clients which use the interconnect APIs to
get paths between endpoints and set their bandwidth/latency/QoS requirements
for these interconnect paths. These interfaces are not currently
documented.
+
+Interconnect debugfs interfaces
+-------------------------------
+
+Like several other subsystems interconnect will create some files for debugging
+and introspection. Files in debugfs are not considered ABI so application
+software shouldn't rely on format details change between kernel versions.
+
+``/sys/kernel/debug/interconnect/interconnect_summary``:
+
+Show all interconnect nodes in the system with their aggregated bandwidth
+request. Indented under each node show bandwidth requests from each device.
+
+``/sys/kernel/debug/interconnect/interconnect_graph``:
+
+Show the interconnect graph in the graphviz dot format. It shows all
+interconnect nodes and links in the system and groups together nodes from the
+same provider as subgraphs. The format is human-readable and can also be piped
+through dot to generate diagrams in many graphical formats::
+
+ $ cat /sys/kernel/debug/interconnect/interconnect_graph | \
+ dot -Tsvg > interconnect_graph.svg
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index b2dad43dbf82..9fcc761031d8 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -5199,10 +5199,11 @@ err_bad_arg:
static int binder_open(struct inode *nodp, struct file *filp)
{
- struct binder_proc *proc;
+ struct binder_proc *proc, *itr;
struct binder_device *binder_dev;
struct binderfs_info *info;
struct dentry *binder_binderfs_dir_entry_proc = NULL;
+ bool existing_pid = false;
binder_debug(BINDER_DEBUG_OPEN_CLOSE, "%s: %d:%d\n", __func__,
current->group_leader->pid, current->pid);
@@ -5235,19 +5236,24 @@ static int binder_open(struct inode *nodp, struct file *filp)
filp->private_data = proc;
mutex_lock(&binder_procs_lock);
+ hlist_for_each_entry(itr, &binder_procs, proc_node) {
+ if (itr->pid == proc->pid) {
+ existing_pid = true;
+ break;
+ }
+ }
hlist_add_head(&proc->proc_node, &binder_procs);
mutex_unlock(&binder_procs_lock);
- if (binder_debugfs_dir_entry_proc) {
+ if (binder_debugfs_dir_entry_proc && !existing_pid) {
char strbuf[11];
snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
/*
- * proc debug entries are shared between contexts, so
- * this will fail if the process tries to open the driver
- * again with a different context. The priting code will
- * anyway print all contexts that a given PID has, so this
- * is not a problem.
+ * proc debug entries are shared between contexts.
+ * Only create for the first PID to avoid debugfs log spamming
+ * The printing code will anyway print all contexts for a given
+ * PID so this is not a problem.
*/
proc->debugfs_entry = debugfs_create_file(strbuf, 0444,
binder_debugfs_dir_entry_proc,
@@ -5255,19 +5261,16 @@ static int binder_open(struct inode *nodp, struct file *filp)
&proc_fops);
}
- if (binder_binderfs_dir_entry_proc) {
+ if (binder_binderfs_dir_entry_proc && !existing_pid) {
char strbuf[11];
struct dentry *binderfs_entry;
snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
/*
* Similar to debugfs, the process specific log file is shared
- * between contexts. If the file has already been created for a
- * process, the following binderfs_create_file() call will
- * fail with error code EEXIST if another context of the same
- * process invoked binder_open(). This is ok since same as
- * debugfs, the log file will contain information on all
- * contexts of a given PID.
+ * between contexts. Only create for the first PID.
+ * This is ok since same as debugfs, the log file will contain
+ * information on all contexts of a given PID.
*/
binderfs_entry = binderfs_create_file(binder_binderfs_dir_entry_proc,
strbuf, &proc_fops, (void *)(unsigned long)proc->pid);
@@ -5277,10 +5280,8 @@ static int binder_open(struct inode *nodp, struct file *filp)
int error;
error = PTR_ERR(binderfs_entry);
- if (error != -EEXIST) {
- pr_warn("Unable to create file %s in binderfs (error %d)\n",
- strbuf, error);
- }
+ pr_warn("Unable to create file %s in binderfs (error %d)\n",
+ strbuf, error);
}
}
diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
index a07cc19becdb..c78d10ea641f 100644
--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
+++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
@@ -715,9 +715,9 @@ EXPORT_SYMBOL_GPL(fsl_mc_device_remove);
struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev)
{
struct fsl_mc_device *mc_bus_dev, *endpoint;
- struct fsl_mc_obj_desc endpoint_desc = { 0 };
- struct dprc_endpoint endpoint1 = { 0 };
- struct dprc_endpoint endpoint2 = { 0 };
+ struct fsl_mc_obj_desc endpoint_desc = {{ 0 }};
+ struct dprc_endpoint endpoint1 = {{ 0 }};
+ struct dprc_endpoint endpoint2 = {{ 0 }};
int state, err;
mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent);
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 9ac6671bb514..aed2c45f7968 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -110,7 +110,7 @@ struct hpets {
unsigned long hp_delta;
unsigned int hp_ntimer;
unsigned int hp_which;
- struct hpet_dev hp_dev[1];
+ struct hpet_dev hp_dev[];
};
static struct hpets *hpets;
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index e970134c95fa..7401733db08b 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -77,8 +77,6 @@ struct arizona_extcon_info {
const struct arizona_micd_range *micd_ranges;
int num_micd_ranges;
- int micd_timeout;
-
bool micd_reva;
bool micd_clamp;
@@ -310,9 +308,13 @@ static void arizona_start_mic(struct arizona_extcon_info *info)
}
if (info->micd_reva) {
- regmap_write(arizona->regmap, 0x80, 0x3);
- regmap_write(arizona->regmap, 0x294, 0);
- regmap_write(arizona->regmap, 0x80, 0x0);
+ const struct reg_sequence reva[] = {
+ { 0x80, 0x3 },
+ { 0x294, 0x0 },
+ { 0x80, 0x0 },
+ };
+
+ regmap_multi_reg_write(arizona->regmap, reva, ARRAY_SIZE(reva));
}
if (info->detecting && arizona->pdata.micd_software_compare)
@@ -361,9 +363,13 @@ static void arizona_stop_mic(struct arizona_extcon_info *info)
snd_soc_dapm_sync(dapm);
if (info->micd_reva) {
- regmap_write(arizona->regmap, 0x80, 0x3);
- regmap_write(arizona->regmap, 0x294, 2);
- regmap_write(arizona->regmap, 0x80, 0x0);
+ const struct reg_sequence reva[] = {
+ { 0x80, 0x3 },
+ { 0x294, 0x2 },
+ { 0x80, 0x0 },
+ };
+
+ regmap_multi_reg_write(arizona->regmap, reva, ARRAY_SIZE(reva));
}
ret = regulator_allow_bypass(info->micvdd, true);
@@ -527,67 +533,65 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
struct arizona *arizona = info->arizona;
int id_gpio = arizona->pdata.hpdet_id_gpio;
+ if (!arizona->pdata.hpdet_acc_id)
+ return 0;
+
/*
* If we're using HPDET for accessory identification we need
* to take multiple measurements, step through them in sequence.
*/
- if (arizona->pdata.hpdet_acc_id) {
- info->hpdet_res[info->num_hpdet_res++] = *reading;
+ info->hpdet_res[info->num_hpdet_res++] = *reading;
- /* Only check the mic directly if we didn't already ID it */
- if (id_gpio && info->num_hpdet_res == 1) {
- dev_dbg(arizona->dev, "Measuring mic\n");
+ /* Only check the mic directly if we didn't already ID it */
+ if (id_gpio && info->num_hpdet_res == 1) {
+ dev_dbg(arizona->dev, "Measuring mic\n");
- regmap_update_bits(arizona->regmap,
- ARIZONA_ACCESSORY_DETECT_MODE_1,
- ARIZONA_ACCDET_MODE_MASK |
- ARIZONA_ACCDET_SRC,
- ARIZONA_ACCDET_MODE_HPR |
- info->micd_modes[0].src);
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_ACCESSORY_DETECT_MODE_1,
+ ARIZONA_ACCDET_MODE_MASK |
+ ARIZONA_ACCDET_SRC,
+ ARIZONA_ACCDET_MODE_HPR |
+ info->micd_modes[0].src);
- gpio_set_value_cansleep(id_gpio, 1);
+ gpio_set_value_cansleep(id_gpio, 1);
- regmap_update_bits(arizona->regmap,
- ARIZONA_HEADPHONE_DETECT_1,
- ARIZONA_HP_POLL, ARIZONA_HP_POLL);
- return -EAGAIN;
- }
-
- /* OK, got both. Now, compare... */
- dev_dbg(arizona->dev, "HPDET measured %d %d\n",
- info->hpdet_res[0], info->hpdet_res[1]);
+ regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
+ ARIZONA_HP_POLL, ARIZONA_HP_POLL);
+ return -EAGAIN;
+ }
- /* Take the headphone impedance for the main report */
- *reading = info->hpdet_res[0];
+ /* OK, got both. Now, compare... */
+ dev_dbg(arizona->dev, "HPDET measured %d %d\n",
+ info->hpdet_res[0], info->hpdet_res[1]);
- /* Sometimes we get false readings due to slow insert */
- if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
- dev_dbg(arizona->dev, "Retrying high impedance\n");
- info->num_hpdet_res = 0;
- info->hpdet_retried = true;
- arizona_start_hpdet_acc_id(info);
- pm_runtime_put(info->dev);
- return -EAGAIN;
- }
+ /* Take the headphone impedance for the main report */
+ *reading = info->hpdet_res[0];
- /*
- * If we measure the mic as high impedance
- */
- if (!id_gpio || info->hpdet_res[1] > 50) {
- dev_dbg(arizona->dev, "Detected mic\n");
- *mic = true;
- info->detecting = true;
- } else {
- dev_dbg(arizona->dev, "Detected headphone\n");
- }
+ /* Sometimes we get false readings due to slow insert */
+ if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
+ dev_dbg(arizona->dev, "Retrying high impedance\n");
+ info->num_hpdet_res = 0;
+ info->hpdet_retried = true;
+ arizona_start_hpdet_acc_id(info);
+ pm_runtime_put(info->dev);
+ return -EAGAIN;
+ }
- /* Make sure everything is reset back to the real polarity */
- regmap_update_bits(arizona->regmap,
- ARIZONA_ACCESSORY_DETECT_MODE_1,
- ARIZONA_ACCDET_SRC,
- info->micd_modes[0].src);
+ /*
+ * If we measure the mic as high impedance
+ */
+ if (!id_gpio || info->hpdet_res[1] > 50) {
+ dev_dbg(arizona->dev, "Detected mic\n");
+ *mic = true;
+ info->detecting = true;
+ } else {
+ dev_dbg(arizona->dev, "Detected headphone\n");
}
+ /* Make sure everything is reset back to the real polarity */
+ regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
+ ARIZONA_ACCDET_SRC, info->micd_modes[0].src);
+
return 0;
}
@@ -662,11 +666,6 @@ done:
if (id_gpio)
gpio_set_value_cansleep(id_gpio, 0);
- /* Revert back to MICDET mode */
- regmap_update_bits(arizona->regmap,
- ARIZONA_ACCESSORY_DETECT_MODE_1,
- ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
-
/* If we have a mic then reenable MICDET */
if (mic || info->mic)
arizona_start_mic(info);
@@ -699,8 +698,7 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info)
info->hpdet_active = true;
- if (info->mic)
- arizona_stop_mic(info);
+ arizona_stop_mic(info);
arizona_extcon_hp_clamp(info, true);
@@ -724,8 +722,8 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info)
return;
err:
- regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
- ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
+ arizona_extcon_hp_clamp(info, false);
+ pm_runtime_put_autosuspend(info->dev);
/* Just report headphone */
ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true);
@@ -781,9 +779,6 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
return;
err:
- regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
- ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
-
/* Just report headphone */
ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true);
if (ret != 0)
@@ -806,75 +801,58 @@ static void arizona_micd_timeout_work(struct work_struct *work)
arizona_identify_headphone(info);
- arizona_stop_mic(info);
-
mutex_unlock(&info->lock);
}
-static void arizona_micd_detect(struct work_struct *work)
+static int arizona_micd_adc_read(struct arizona_extcon_info *info)
{
- struct arizona_extcon_info *info = container_of(work,
- struct arizona_extcon_info,
- micd_detect_work.work);
struct arizona *arizona = info->arizona;
- unsigned int val = 0, lvl;
- int ret, i, key;
-
- cancel_delayed_work_sync(&info->micd_timeout_work);
+ unsigned int val;
+ int ret;
- mutex_lock(&info->lock);
+ /* Must disable MICD before we read the ADCVAL */
+ regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
+ ARIZONA_MICD_ENA, 0);
- /* If the cable was removed while measuring ignore the result */
- ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
- if (ret < 0) {
- dev_err(arizona->dev, "Failed to check cable state: %d\n",
- ret);
- mutex_unlock(&info->lock);
- return;
- } else if (!ret) {
- dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
- mutex_unlock(&info->lock);
- return;
+ ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_4, &val);
+ if (ret != 0) {
+ dev_err(arizona->dev,
+ "Failed to read MICDET_ADCVAL: %d\n", ret);
+ return ret;
}
- if (info->detecting && arizona->pdata.micd_software_compare) {
- /* Must disable MICD before we read the ADCVAL */
- regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
- ARIZONA_MICD_ENA, 0);
- ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_4, &val);
- if (ret != 0) {
- dev_err(arizona->dev,
- "Failed to read MICDET_ADCVAL: %d\n",
- ret);
- mutex_unlock(&info->lock);
- return;
- }
+ dev_dbg(arizona->dev, "MICDET_ADCVAL: %x\n", val);
- dev_dbg(arizona->dev, "MICDET_ADCVAL: %x\n", val);
+ val &= ARIZONA_MICDET_ADCVAL_MASK;
+ if (val < ARRAY_SIZE(arizona_micd_levels))
+ val = arizona_micd_levels[val];
+ else
+ val = INT_MAX;
+
+ if (val <= QUICK_HEADPHONE_MAX_OHM)
+ val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_0;
+ else if (val <= MICROPHONE_MIN_OHM)
+ val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_1;
+ else if (val <= MICROPHONE_MAX_OHM)
+ val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_8;
+ else
+ val = ARIZONA_MICD_LVL_8;
- val &= ARIZONA_MICDET_ADCVAL_MASK;
- if (val < ARRAY_SIZE(arizona_micd_levels))
- val = arizona_micd_levels[val];
- else
- val = INT_MAX;
-
- if (val <= QUICK_HEADPHONE_MAX_OHM)
- val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_0;
- else if (val <= MICROPHONE_MIN_OHM)
- val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_1;
- else if (val <= MICROPHONE_MAX_OHM)
- val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_8;
- else
- val = ARIZONA_MICD_LVL_8;
- }
+ return val;
+}
+
+static int arizona_micd_read(struct arizona_extcon_info *info)
+{
+ struct arizona *arizona = info->arizona;
+ unsigned int val = 0;
+ int ret, i;
for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
if (ret != 0) {
dev_err(arizona->dev,
"Failed to read MICDET: %d\n", ret);
- mutex_unlock(&info->lock);
- return;
+ return ret;
}
dev_dbg(arizona->dev, "MICDET: %x\n", val);
@@ -882,29 +860,44 @@ static void arizona_micd_detect(struct work_struct *work)
if (!(val & ARIZONA_MICD_VALID)) {
dev_warn(arizona->dev,
"Microphone detection state invalid\n");
- mutex_unlock(&info->lock);
- return;
+ return -EINVAL;
}
}
if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
dev_err(arizona->dev, "Failed to get valid MICDET value\n");
- mutex_unlock(&info->lock);
- return;
+ return -EINVAL;
}
+ return val;
+}
+
+static int arizona_micdet_reading(void *priv)
+{
+ struct arizona_extcon_info *info = priv;
+ struct arizona *arizona = info->arizona;
+ int ret, val;
+
+ if (info->detecting && arizona->pdata.micd_software_compare)
+ ret = arizona_micd_adc_read(info);
+ else
+ ret = arizona_micd_read(info);
+ if (ret < 0)
+ return ret;
+
+ val = ret;
+
/* Due to jack detect this should never happen */
if (!(val & ARIZONA_MICD_STS)) {
dev_warn(arizona->dev, "Detected open circuit\n");
info->mic = false;
- arizona_stop_mic(info);
info->detecting = false;
arizona_identify_headphone(info);
- goto handled;
+ return 0;
}
/* If we got a high impedence we should have a headset, report it. */
- if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
+ if (val & ARIZONA_MICD_LVL_8) {
info->mic = true;
info->detecting = false;
@@ -923,7 +916,7 @@ static void arizona_micd_detect(struct work_struct *work)
ret);
}
- goto handled;
+ return 0;
}
/* If we detected a lower impedence during initial startup
@@ -932,15 +925,13 @@ static void arizona_micd_detect(struct work_struct *work)
* plain headphones. If both polarities report a low
* impedence then give up and report headphones.
*/
- if (info->detecting && (val & MICD_LVL_1_TO_7)) {
+ if (val & MICD_LVL_1_TO_7) {
if (info->jack_flips >= info->micd_num_modes * 10) {
dev_dbg(arizona->dev, "Detected HP/line\n");
info->detecting = false;
arizona_identify_headphone(info);
-
- arizona_stop_mic(info);
} else {
info->micd_mode++;
if (info->micd_mode == info->micd_num_modes)
@@ -948,13 +939,45 @@ static void arizona_micd_detect(struct work_struct *work)
arizona_extcon_set_mode(info, info->micd_mode);
info->jack_flips++;
+
+ if (arizona->pdata.micd_software_compare)
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_MIC_DETECT_1,
+ ARIZONA_MICD_ENA,
+ ARIZONA_MICD_ENA);
+
+ queue_delayed_work(system_power_efficient_wq,
+ &info->micd_timeout_work,
+ msecs_to_jiffies(arizona->pdata.micd_timeout));
}
- goto handled;
+ return 0;
}
/*
* If we're still detecting and we detect a short then we've
+ * got a headphone.
+ */
+ dev_dbg(arizona->dev, "Headphone detected\n");
+ info->detecting = false;
+
+ arizona_identify_headphone(info);
+
+ return 0;
+}
+
+static int arizona_button_reading(void *priv)
+{
+ struct arizona_extcon_info *info = priv;
+ struct arizona *arizona = info->arizona;
+ int val, key, lvl, i;
+
+ val = arizona_micd_read(info);
+ if (val < 0)
+ return val;
+
+ /*
+ * If we're still detecting and we detect a short then we've
* got a headphone. Otherwise it's a button press.
*/
if (val & MICD_LVL_0_TO_7) {
@@ -968,20 +991,13 @@ static void arizona_micd_detect(struct work_struct *work)
input_report_key(info->input,
info->micd_ranges[i].key, 0);
- WARN_ON(!lvl);
- WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
key = info->micd_ranges[ffs(lvl) - 1].key;
input_report_key(info->input, key, 1);
input_sync(info->input);
+ } else {
+ dev_err(arizona->dev, "Button out of range\n");
}
-
- } else if (info->detecting) {
- dev_dbg(arizona->dev, "Headphone detected\n");
- info->detecting = false;
- arizona_stop_mic(info);
-
- arizona_identify_headphone(info);
} else {
dev_warn(arizona->dev, "Button with no mic: %x\n",
val);
@@ -995,19 +1011,39 @@ static void arizona_micd_detect(struct work_struct *work)
arizona_extcon_pulse_micbias(info);
}
-handled:
- if (info->detecting) {
- if (arizona->pdata.micd_software_compare)
- regmap_update_bits(arizona->regmap,
- ARIZONA_MIC_DETECT_1,
- ARIZONA_MICD_ENA,
- ARIZONA_MICD_ENA);
+ return 0;
+}
- queue_delayed_work(system_power_efficient_wq,
- &info->micd_timeout_work,
- msecs_to_jiffies(info->micd_timeout));
+static void arizona_micd_detect(struct work_struct *work)
+{
+ struct arizona_extcon_info *info = container_of(work,
+ struct arizona_extcon_info,
+ micd_detect_work.work);
+ struct arizona *arizona = info->arizona;
+ int ret;
+
+ cancel_delayed_work_sync(&info->micd_timeout_work);
+
+ mutex_lock(&info->lock);
+
+ /* If the cable was removed while measuring ignore the result */
+ ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
+ if (ret < 0) {
+ dev_err(arizona->dev, "Failed to check cable state: %d\n",
+ ret);
+ mutex_unlock(&info->lock);
+ return;
+ } else if (!ret) {
+ dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
+ mutex_unlock(&info->lock);
+ return;
}
+ if (info->detecting)
+ arizona_micdet_reading(info);
+ else
+ arizona_button_reading(info);
+
pm_runtime_mark_last_busy(info->dev);
mutex_unlock(&info->lock);
}
@@ -1125,7 +1161,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
msecs_to_jiffies(HPDET_DEBOUNCE));
if (cancelled_mic) {
- int micd_timeout = info->micd_timeout;
+ int micd_timeout = arizona->pdata.micd_timeout;
queue_delayed_work(system_power_efficient_wq,
&info->micd_timeout_work,
@@ -1145,11 +1181,11 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
dev_err(arizona->dev, "Mechanical report failed: %d\n",
ret);
- if (!arizona->pdata.hpdet_acc_id) {
- info->detecting = true;
- info->mic = false;
- info->jack_flips = 0;
+ info->detecting = true;
+ info->mic = false;
+ info->jack_flips = 0;
+ if (!arizona->pdata.hpdet_acc_id) {
arizona_start_mic(info);
} else {
queue_delayed_work(system_power_efficient_wq,
@@ -1202,11 +1238,6 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
}
- if (arizona->pdata.micd_timeout)
- info->micd_timeout = arizona->pdata.micd_timeout;
- else
- info->micd_timeout = DEFAULT_MICD_TIMEOUT;
-
out:
/* Clear trig_sts to make sure DCVDD is not forced up */
regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
@@ -1435,6 +1466,9 @@ static int arizona_extcon_probe(struct platform_device *pdev)
info->input->name = "Headset";
info->input->phys = "arizona/extcon";
+ if (!pdata->micd_timeout)
+ pdata->micd_timeout = DEFAULT_MICD_TIMEOUT;
+
if (pdata->num_micd_configs) {
info->micd_modes = pdata->micd_configs;
info->micd_num_modes = pdata->num_micd_configs;
diff --git a/drivers/extcon/extcon-sm5502.c b/drivers/extcon/extcon-sm5502.c
index bcf65aaca5d2..106d4da647bd 100644
--- a/drivers/extcon/extcon-sm5502.c
+++ b/drivers/extcon/extcon-sm5502.c
@@ -249,7 +249,7 @@ static int sm5502_muic_set_path(struct sm5502_muic_info *info,
dev_err(info->dev, "Unknown DM_CON/DP_CON switch type (%d)\n",
con_sw);
return -EINVAL;
- };
+ }
switch (vbus_sw) {
case VBUSIN_SWITCH_OPEN:
@@ -268,7 +268,7 @@ static int sm5502_muic_set_path(struct sm5502_muic_info *info,
default:
dev_err(info->dev, "Unknown VBUS switch type (%d)\n", vbus_sw);
return -EINVAL;
- };
+ }
return 0;
}
@@ -357,13 +357,13 @@ static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info)
"cannot identify the cable type: adc(0x%x)\n",
adc);
return -EINVAL;
- };
+ }
break;
default:
dev_err(info->dev,
"failed to identify the cable type: adc(0x%x)\n", adc);
return -EINVAL;
- };
+ }
return cable_type;
}
@@ -405,7 +405,7 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info,
dev_dbg(info->dev,
"cannot handle this cable_type (0x%x)\n", cable_type);
return 0;
- };
+ }
/* Change internal hardware path(DM_CON/DP_CON, VBUSIN) */
ret = sm5502_muic_set_path(info, con_sw, vbus_sw, attached);
diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c
index 8d132e4f008a..0205987a4fd4 100644
--- a/drivers/firmware/google/coreboot_table.c
+++ b/drivers/firmware/google/coreboot_table.c
@@ -163,8 +163,15 @@ static int coreboot_table_probe(struct platform_device *pdev)
return ret;
}
+static int __cb_dev_unregister(struct device *dev, void *dummy)
+{
+ device_unregister(dev);
+ return 0;
+}
+
static int coreboot_table_remove(struct platform_device *pdev)
{
+ bus_for_each_dev(&coreboot_bus_type, NULL, NULL, __cb_dev_unregister);
bus_unregister(&coreboot_bus_type);
return 0;
}
diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c
index edaa4e5d84ad..5b2011ebbe26 100644
--- a/drivers/firmware/google/gsmi.c
+++ b/drivers/firmware/google/gsmi.c
@@ -76,6 +76,7 @@
#define GSMI_CMD_LOG_S0IX_RESUME 0x0b
#define GSMI_CMD_CLEAR_CONFIG 0x20
#define GSMI_CMD_HANDSHAKE_TYPE 0xC1
+#define GSMI_CMD_RESERVED 0xff
/* Magic entry type for kernel events */
#define GSMI_LOG_ENTRY_TYPE_KERNEL 0xDEAD
@@ -746,6 +747,7 @@ MODULE_DEVICE_TABLE(dmi, gsmi_dmi_table);
static __init int gsmi_system_valid(void)
{
u32 hash;
+ u16 cmd, result;
if (!dmi_check_system(gsmi_dmi_table))
return -ENODEV;
@@ -780,6 +782,23 @@ static __init int gsmi_system_valid(void)
return -ENODEV;
}
+ /* Test the smihandler with a bogus command. If it leaves the
+ * calling argument in %ax untouched, there is no handler for
+ * GSMI commands.
+ */
+ cmd = GSMI_CALLBACK | GSMI_CMD_RESERVED << 8;
+ asm volatile (
+ "outb %%al, %%dx\n\t"
+ : "=a" (result)
+ : "0" (cmd),
+ "d" (acpi_gbl_FADT.smi_command)
+ : "memory", "cc"
+ );
+ if (cmd == result) {
+ pr_info("gsmi: no gsmi handler in firmware\n");
+ return -ENODEV;
+ }
+
/* Found */
return 0;
}
@@ -1016,6 +1035,9 @@ out_err:
dma_pool_destroy(gsmi_dev.dma_pool);
platform_device_unregister(gsmi_dev.pdev);
pr_info("gsmi: failed to load: %d\n", ret);
+#ifdef CONFIG_PM
+ platform_driver_unregister(&gsmi_driver_info);
+#endif
return ret;
}
@@ -1037,6 +1059,9 @@ static void __exit gsmi_exit(void)
gsmi_buf_free(gsmi_dev.name_buf);
dma_pool_destroy(gsmi_dev.dma_pool);
platform_device_unregister(gsmi_dev.pdev);
+#ifdef CONFIG_PM
+ platform_driver_unregister(&gsmi_driver_info);
+#endif
}
module_init(gsmi_init);
diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c
index c6c31402848d..7ffb42b0775e 100644
--- a/drivers/firmware/stratix10-svc.c
+++ b/drivers/firmware/stratix10-svc.c
@@ -268,7 +268,7 @@ static void svc_thread_cmd_config_status(struct stratix10_svc_controller *ctrl,
*/
msleep(1000);
count_in_sec--;
- };
+ }
if (res.a0 == INTEL_SIP_SMC_STATUS_OK && count_in_sec)
cb_data->status = BIT(SVC_STATUS_RECONFIG_COMPLETED);
@@ -512,7 +512,7 @@ static int svc_normal_to_secure_thread(void *data)
break;
}
- };
+ }
kfree(cbdata);
kfree(pdata);
diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c
index e4a34dc7947f..65437b6a6842 100644
--- a/drivers/fpga/dfl-afu-main.c
+++ b/drivers/fpga/dfl-afu-main.c
@@ -813,10 +813,8 @@ static int afu_dev_init(struct platform_device *pdev)
static int afu_dev_destroy(struct platform_device *pdev)
{
struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
- struct dfl_afu *afu;
mutex_lock(&pdata->lock);
- afu = dfl_fpga_pdata_get_private(pdata);
afu_mmio_region_destroy(pdata);
afu_dma_region_destroy(pdata);
dfl_fpga_pdata_set_private(pdata, NULL);
diff --git a/drivers/fpga/dfl-fme-main.c b/drivers/fpga/dfl-fme-main.c
index 7c930e6b314d..1d4690c99268 100644
--- a/drivers/fpga/dfl-fme-main.c
+++ b/drivers/fpga/dfl-fme-main.c
@@ -675,10 +675,8 @@ static int fme_dev_init(struct platform_device *pdev)
static void fme_dev_destroy(struct platform_device *pdev)
{
struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
- struct dfl_fme *fme;
mutex_lock(&pdata->lock);
- fme = dfl_fpga_pdata_get_private(pdata);
dfl_fpga_pdata_set_private(pdata, NULL);
mutex_unlock(&pdata->lock);
}
diff --git a/drivers/fpga/ts73xx-fpga.c b/drivers/fpga/ts73xx-fpga.c
index 9a17fe98c1b0..2888ff000e4d 100644
--- a/drivers/fpga/ts73xx-fpga.c
+++ b/drivers/fpga/ts73xx-fpga.c
@@ -119,10 +119,8 @@ static int ts73xx_fpga_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->io_base = devm_ioremap_resource(kdev, res);
- if (IS_ERR(priv->io_base)) {
- dev_err(kdev, "unable to remap registers\n");
+ if (IS_ERR(priv->io_base))
return PTR_ERR(priv->io_base);
- }
mgr = devm_fpga_mgr_create(kdev, "TS-73xx FPGA Manager",
&ts73xx_fpga_ops, priv);
diff --git a/drivers/fpga/xilinx-pr-decoupler.c b/drivers/fpga/xilinx-pr-decoupler.c
index af9b387c56d3..7d69af230567 100644
--- a/drivers/fpga/xilinx-pr-decoupler.c
+++ b/drivers/fpga/xilinx-pr-decoupler.c
@@ -101,7 +101,8 @@ static int xlnx_pr_decoupler_probe(struct platform_device *pdev)
priv->clk = devm_clk_get(&pdev->dev, "aclk");
if (IS_ERR(priv->clk)) {
- dev_err(&pdev->dev, "input clock not found\n");
+ if (PTR_ERR(priv->clk) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "input clock not found\n");
return PTR_ERR(priv->clk);
}
diff --git a/drivers/interconnect/Makefile b/drivers/interconnect/Makefile
index 28f2ab0824d5..725029ae7a2c 100644
--- a/drivers/interconnect/Makefile
+++ b/drivers/interconnect/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
+CFLAGS_core.o := -I$(src)
icc-core-objs := core.o
obj-$(CONFIG_INTERCONNECT) += icc-core.o
diff --git a/drivers/interconnect/core.c b/drivers/interconnect/core.c
index c498796adc07..f277e467156f 100644
--- a/drivers/interconnect/core.c
+++ b/drivers/interconnect/core.c
@@ -19,45 +19,22 @@
#include <linux/of.h>
#include <linux/overflow.h>
+#include "internal.h"
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
static DEFINE_IDR(icc_idr);
static LIST_HEAD(icc_providers);
static DEFINE_MUTEX(icc_lock);
static struct dentry *icc_debugfs_dir;
-/**
- * struct icc_req - constraints that are attached to each node
- * @req_node: entry in list of requests for the particular @node
- * @node: the interconnect node to which this constraint applies
- * @dev: reference to the device that sets the constraints
- * @tag: path tag (optional)
- * @avg_bw: an integer describing the average bandwidth in kBps
- * @peak_bw: an integer describing the peak bandwidth in kBps
- */
-struct icc_req {
- struct hlist_node req_node;
- struct icc_node *node;
- struct device *dev;
- u32 tag;
- u32 avg_bw;
- u32 peak_bw;
-};
-
-/**
- * struct icc_path - interconnect path structure
- * @num_nodes: number of hops (nodes)
- * @reqs: array of the requests applicable to this path of nodes
- */
-struct icc_path {
- size_t num_nodes;
- struct icc_req reqs[];
-};
-
static void icc_summary_show_one(struct seq_file *s, struct icc_node *n)
{
if (!n)
return;
- seq_printf(s, "%-30s %12u %12u\n",
+ seq_printf(s, "%-42s %12u %12u\n",
n->name, n->avg_bw, n->peak_bw);
}
@@ -65,8 +42,8 @@ static int icc_summary_show(struct seq_file *s, void *data)
{
struct icc_provider *provider;
- seq_puts(s, " node avg peak\n");
- seq_puts(s, "--------------------------------------------------------\n");
+ seq_puts(s, " node tag avg peak\n");
+ seq_puts(s, "--------------------------------------------------------------------\n");
mutex_lock(&icc_lock);
@@ -81,8 +58,8 @@ static int icc_summary_show(struct seq_file *s, void *data)
if (!r->dev)
continue;
- seq_printf(s, " %-26s %12u %12u\n",
- dev_name(r->dev), r->avg_bw,
+ seq_printf(s, " %-27s %12u %12u %12u\n",
+ dev_name(r->dev), r->tag, r->avg_bw,
r->peak_bw);
}
}
@@ -94,6 +71,70 @@ static int icc_summary_show(struct seq_file *s, void *data)
}
DEFINE_SHOW_ATTRIBUTE(icc_summary);
+static void icc_graph_show_link(struct seq_file *s, int level,
+ struct icc_node *n, struct icc_node *m)
+{
+ seq_printf(s, "%s\"%d:%s\" -> \"%d:%s\"\n",
+ level == 2 ? "\t\t" : "\t",
+ n->id, n->name, m->id, m->name);
+}
+
+static void icc_graph_show_node(struct seq_file *s, struct icc_node *n)
+{
+ seq_printf(s, "\t\t\"%d:%s\" [label=\"%d:%s",
+ n->id, n->name, n->id, n->name);
+ seq_printf(s, "\n\t\t\t|avg_bw=%ukBps", n->avg_bw);
+ seq_printf(s, "\n\t\t\t|peak_bw=%ukBps", n->peak_bw);
+ seq_puts(s, "\"]\n");
+}
+
+static int icc_graph_show(struct seq_file *s, void *data)
+{
+ struct icc_provider *provider;
+ struct icc_node *n;
+ int cluster_index = 0;
+ int i;
+
+ seq_puts(s, "digraph {\n\trankdir = LR\n\tnode [shape = record]\n");
+ mutex_lock(&icc_lock);
+
+ /* draw providers as cluster subgraphs */
+ cluster_index = 0;
+ list_for_each_entry(provider, &icc_providers, provider_list) {
+ seq_printf(s, "\tsubgraph cluster_%d {\n", ++cluster_index);
+ if (provider->dev)
+ seq_printf(s, "\t\tlabel = \"%s\"\n",
+ dev_name(provider->dev));
+
+ /* draw nodes */
+ list_for_each_entry(n, &provider->nodes, node_list)
+ icc_graph_show_node(s, n);
+
+ /* draw internal links */
+ list_for_each_entry(n, &provider->nodes, node_list)
+ for (i = 0; i < n->num_links; ++i)
+ if (n->provider == n->links[i]->provider)
+ icc_graph_show_link(s, 2, n,
+ n->links[i]);
+
+ seq_puts(s, "\t}\n");
+ }
+
+ /* draw external links */
+ list_for_each_entry(provider, &icc_providers, provider_list)
+ list_for_each_entry(n, &provider->nodes, node_list)
+ for (i = 0; i < n->num_links; ++i)
+ if (n->provider != n->links[i]->provider)
+ icc_graph_show_link(s, 1, n,
+ n->links[i]);
+
+ mutex_unlock(&icc_lock);
+ seq_puts(s, "}");
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(icc_graph);
+
static struct icc_node *node_find(const int id)
{
return idr_find(&icc_idr, id);
@@ -244,6 +285,16 @@ out:
return ret;
}
+int icc_std_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
+ u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
+{
+ *agg_avg += avg_bw;
+ *agg_peak = max(*agg_peak, peak_bw);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(icc_std_aggregate);
+
/* of_icc_xlate_onecell() - Translate function using a single index.
* @spec: OF phandle args to map into an interconnect node.
* @data: private data (pointer to struct icc_onecell_data)
@@ -382,9 +433,17 @@ struct icc_path *of_icc_get(struct device *dev, const char *name)
mutex_lock(&icc_lock);
path = path_find(dev, src_node, dst_node);
- if (IS_ERR(path))
- dev_err(dev, "%s: invalid path=%ld\n", __func__, PTR_ERR(path));
mutex_unlock(&icc_lock);
+ if (IS_ERR(path)) {
+ dev_err(dev, "%s: invalid path=%ld\n", __func__, PTR_ERR(path));
+ return path;
+ }
+
+ if (name)
+ path->name = kstrdup_const(name, GFP_KERNEL);
+ else
+ path->name = kasprintf(GFP_KERNEL, "%s-%s",
+ src_node->name, dst_node->name);
return path;
}
@@ -436,9 +495,12 @@ int icc_set_bw(struct icc_path *path, u32 avg_bw, u32 peak_bw)
size_t i;
int ret;
- if (!path || !path->num_nodes)
+ if (!path)
return 0;
+ if (WARN_ON(IS_ERR(path) || !path->num_nodes))
+ return -EINVAL;
+
mutex_lock(&icc_lock);
old_avg = path->reqs[0].avg_bw;
@@ -453,6 +515,8 @@ int icc_set_bw(struct icc_path *path, u32 avg_bw, u32 peak_bw)
/* aggregate requests for this node */
aggregate_requests(node);
+
+ trace_icc_set_bw(path, node, i, avg_bw, peak_bw);
}
ret = apply_constraints(path);
@@ -471,6 +535,8 @@ int icc_set_bw(struct icc_path *path, u32 avg_bw, u32 peak_bw)
mutex_unlock(&icc_lock);
+ trace_icc_set_bw_end(path, ret);
+
return ret;
}
EXPORT_SYMBOL_GPL(icc_set_bw);
@@ -507,9 +573,12 @@ struct icc_path *icc_get(struct device *dev, const int src_id, const int dst_id)
goto out;
path = path_find(dev, src, dst);
- if (IS_ERR(path))
+ if (IS_ERR(path)) {
dev_err(dev, "%s: invalid path=%ld\n", __func__, PTR_ERR(path));
+ goto out;
+ }
+ path->name = kasprintf(GFP_KERNEL, "%s-%s", src->name, dst->name);
out:
mutex_unlock(&icc_lock);
return path;
@@ -545,6 +614,7 @@ void icc_put(struct icc_path *path)
}
mutex_unlock(&icc_lock);
+ kfree_const(path->name);
kfree(path);
}
EXPORT_SYMBOL_GPL(icc_put);
@@ -743,6 +813,28 @@ void icc_node_del(struct icc_node *node)
EXPORT_SYMBOL_GPL(icc_node_del);
/**
+ * icc_nodes_remove() - remove all previously added nodes from provider
+ * @provider: the interconnect provider we are removing nodes from
+ *
+ * Return: 0 on success, or an error code otherwise
+ */
+int icc_nodes_remove(struct icc_provider *provider)
+{
+ struct icc_node *n, *tmp;
+
+ if (WARN_ON(IS_ERR_OR_NULL(provider)))
+ return -EINVAL;
+
+ list_for_each_entry_safe_reverse(n, tmp, &provider->nodes, node_list) {
+ icc_node_del(n);
+ icc_node_destroy(n->id);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(icc_nodes_remove);
+
+/**
* icc_provider_add() - add a new interconnect provider
* @provider: the interconnect provider that will be added into topology
*
@@ -802,6 +894,8 @@ static int __init icc_init(void)
icc_debugfs_dir = debugfs_create_dir("interconnect", NULL);
debugfs_create_file("interconnect_summary", 0444,
icc_debugfs_dir, NULL, &icc_summary_fops);
+ debugfs_create_file("interconnect_graph", 0444,
+ icc_debugfs_dir, NULL, &icc_graph_fops);
return 0;
}
diff --git a/drivers/interconnect/internal.h b/drivers/interconnect/internal.h
new file mode 100644
index 000000000000..bf18cb7239df
--- /dev/null
+++ b/drivers/interconnect/internal.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Interconnect framework internal structs
+ *
+ * Copyright (c) 2019, Linaro Ltd.
+ * Author: Georgi Djakov <georgi.djakov@linaro.org>
+ */
+
+#ifndef __DRIVERS_INTERCONNECT_INTERNAL_H
+#define __DRIVERS_INTERCONNECT_INTERNAL_H
+
+/**
+ * struct icc_req - constraints that are attached to each node
+ * @req_node: entry in list of requests for the particular @node
+ * @node: the interconnect node to which this constraint applies
+ * @dev: reference to the device that sets the constraints
+ * @tag: path tag (optional)
+ * @avg_bw: an integer describing the average bandwidth in kBps
+ * @peak_bw: an integer describing the peak bandwidth in kBps
+ */
+struct icc_req {
+ struct hlist_node req_node;
+ struct icc_node *node;
+ struct device *dev;
+ u32 tag;
+ u32 avg_bw;
+ u32 peak_bw;
+};
+
+/**
+ * struct icc_path - interconnect path structure
+ * @name: a string name of the path (useful for ftrace)
+ * @num_nodes: number of hops (nodes)
+ * @reqs: array of the requests applicable to this path of nodes
+ */
+struct icc_path {
+ const char *name;
+ size_t num_nodes;
+ struct icc_req reqs[];
+};
+
+#endif
diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig
index 2f9304d1db49..76938ece1658 100644
--- a/drivers/interconnect/qcom/Kconfig
+++ b/drivers/interconnect/qcom/Kconfig
@@ -5,6 +5,15 @@ config INTERCONNECT_QCOM
help
Support for Qualcomm's Network-on-Chip interconnect hardware.
+config INTERCONNECT_QCOM_MSM8916
+ tristate "Qualcomm MSM8916 interconnect driver"
+ depends on INTERCONNECT_QCOM
+ depends on QCOM_SMD_RPM
+ select INTERCONNECT_QCOM_SMD_RPM
+ help
+ This is a driver for the Qualcomm Network-on-Chip on msm8916-based
+ platforms.
+
config INTERCONNECT_QCOM_MSM8974
tristate "Qualcomm MSM8974 interconnect driver"
depends on INTERCONNECT_QCOM
diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom/Makefile
index 9adf9e380545..e8271575e3d8 100644
--- a/drivers/interconnect/qcom/Makefile
+++ b/drivers/interconnect/qcom/Makefile
@@ -1,10 +1,12 @@
# SPDX-License-Identifier: GPL-2.0
+qnoc-msm8916-objs := msm8916.o
qnoc-msm8974-objs := msm8974.o
qnoc-qcs404-objs := qcs404.o
qnoc-sdm845-objs := sdm845.o
icc-smd-rpm-objs := smd-rpm.o
+obj-$(CONFIG_INTERCONNECT_QCOM_MSM8916) += qnoc-msm8916.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8974) += qnoc-msm8974.o
obj-$(CONFIG_INTERCONNECT_QCOM_QCS404) += qnoc-qcs404.o
obj-$(CONFIG_INTERCONNECT_QCOM_SDM845) += qnoc-sdm845.o
diff --git a/drivers/interconnect/qcom/msm8916.c b/drivers/interconnect/qcom/msm8916.c
new file mode 100644
index 000000000000..e94f3c5228b7
--- /dev/null
+++ b/drivers/interconnect/qcom/msm8916.c
@@ -0,0 +1,554 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018-2020 Linaro Ltd
+ * Author: Georgi Djakov <georgi.djakov@linaro.org>
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/interconnect-provider.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+
+#include <dt-bindings/interconnect/qcom,msm8916.h>
+
+#include "smd-rpm.h"
+
+#define RPM_BUS_MASTER_REQ 0x73616d62
+#define RPM_BUS_SLAVE_REQ 0x766c7362
+
+enum {
+ MSM8916_BIMC_SNOC_MAS = 1,
+ MSM8916_BIMC_SNOC_SLV,
+ MSM8916_MASTER_AMPSS_M0,
+ MSM8916_MASTER_LPASS,
+ MSM8916_MASTER_BLSP_1,
+ MSM8916_MASTER_DEHR,
+ MSM8916_MASTER_GRAPHICS_3D,
+ MSM8916_MASTER_JPEG,
+ MSM8916_MASTER_MDP_PORT0,
+ MSM8916_MASTER_CRYPTO_CORE0,
+ MSM8916_MASTER_SDCC_1,
+ MSM8916_MASTER_SDCC_2,
+ MSM8916_MASTER_QDSS_BAM,
+ MSM8916_MASTER_QDSS_ETR,
+ MSM8916_MASTER_SNOC_CFG,
+ MSM8916_MASTER_SPDM,
+ MSM8916_MASTER_TCU0,
+ MSM8916_MASTER_TCU1,
+ MSM8916_MASTER_USB_HS,
+ MSM8916_MASTER_VFE,
+ MSM8916_MASTER_VIDEO_P0,
+ MSM8916_SNOC_MM_INT_0,
+ MSM8916_SNOC_MM_INT_1,
+ MSM8916_SNOC_MM_INT_2,
+ MSM8916_SNOC_MM_INT_BIMC,
+ MSM8916_PNOC_INT_0,
+ MSM8916_PNOC_INT_1,
+ MSM8916_PNOC_MAS_0,
+ MSM8916_PNOC_MAS_1,
+ MSM8916_PNOC_SLV_0,
+ MSM8916_PNOC_SLV_1,
+ MSM8916_PNOC_SLV_2,
+ MSM8916_PNOC_SLV_3,
+ MSM8916_PNOC_SLV_4,
+ MSM8916_PNOC_SLV_8,
+ MSM8916_PNOC_SLV_9,
+ MSM8916_PNOC_SNOC_MAS,
+ MSM8916_PNOC_SNOC_SLV,
+ MSM8916_SNOC_QDSS_INT,
+ MSM8916_SLAVE_AMPSS_L2,
+ MSM8916_SLAVE_APSS,
+ MSM8916_SLAVE_LPASS,
+ MSM8916_SLAVE_BIMC_CFG,
+ MSM8916_SLAVE_BLSP_1,
+ MSM8916_SLAVE_BOOT_ROM,
+ MSM8916_SLAVE_CAMERA_CFG,
+ MSM8916_SLAVE_CATS_128,
+ MSM8916_SLAVE_OCMEM_64,
+ MSM8916_SLAVE_CLK_CTL,
+ MSM8916_SLAVE_CRYPTO_0_CFG,
+ MSM8916_SLAVE_DEHR_CFG,
+ MSM8916_SLAVE_DISPLAY_CFG,
+ MSM8916_SLAVE_EBI_CH0,
+ MSM8916_SLAVE_GRAPHICS_3D_CFG,
+ MSM8916_SLAVE_IMEM_CFG,
+ MSM8916_SLAVE_IMEM,
+ MSM8916_SLAVE_MPM,
+ MSM8916_SLAVE_MSG_RAM,
+ MSM8916_SLAVE_MSS,
+ MSM8916_SLAVE_PDM,
+ MSM8916_SLAVE_PMIC_ARB,
+ MSM8916_SLAVE_PNOC_CFG,
+ MSM8916_SLAVE_PRNG,
+ MSM8916_SLAVE_QDSS_CFG,
+ MSM8916_SLAVE_QDSS_STM,
+ MSM8916_SLAVE_RBCPR_CFG,
+ MSM8916_SLAVE_SDCC_1,
+ MSM8916_SLAVE_SDCC_2,
+ MSM8916_SLAVE_SECURITY,
+ MSM8916_SLAVE_SNOC_CFG,
+ MSM8916_SLAVE_SPDM,
+ MSM8916_SLAVE_SRVC_SNOC,
+ MSM8916_SLAVE_TCSR,
+ MSM8916_SLAVE_TLMM,
+ MSM8916_SLAVE_USB_HS,
+ MSM8916_SLAVE_VENUS_CFG,
+ MSM8916_SNOC_BIMC_0_MAS,
+ MSM8916_SNOC_BIMC_0_SLV,
+ MSM8916_SNOC_BIMC_1_MAS,
+ MSM8916_SNOC_BIMC_1_SLV,
+ MSM8916_SNOC_INT_0,
+ MSM8916_SNOC_INT_1,
+ MSM8916_SNOC_INT_BIMC,
+ MSM8916_SNOC_PNOC_MAS,
+ MSM8916_SNOC_PNOC_SLV,
+};
+
+#define to_msm8916_provider(_provider) \
+ container_of(_provider, struct msm8916_icc_provider, provider)
+
+static const struct clk_bulk_data msm8916_bus_clocks[] = {
+ { .id = "bus" },
+ { .id = "bus_a" },
+};
+
+/**
+ * struct msm8916_icc_provider - Qualcomm specific interconnect provider
+ * @provider: generic interconnect provider
+ * @bus_clks: the clk_bulk_data table of bus clocks
+ * @num_clks: the total number of clk_bulk_data entries
+ */
+struct msm8916_icc_provider {
+ struct icc_provider provider;
+ struct clk_bulk_data *bus_clks;
+ int num_clks;
+};
+
+#define MSM8916_MAX_LINKS 8
+
+/**
+ * struct msm8916_icc_node - Qualcomm specific interconnect nodes
+ * @name: the node name used in debugfs
+ * @id: a unique node identifier
+ * @links: an array of nodes where we can go next while traversing
+ * @num_links: the total number of @links
+ * @buswidth: width of the interconnect between a node and the bus (bytes)
+ * @mas_rpm_id: RPM ID for devices that are bus masters
+ * @slv_rpm_id: RPM ID for devices that are bus slaves
+ * @rate: current bus clock rate in Hz
+ */
+struct msm8916_icc_node {
+ unsigned char *name;
+ u16 id;
+ u16 links[MSM8916_MAX_LINKS];
+ u16 num_links;
+ u16 buswidth;
+ int mas_rpm_id;
+ int slv_rpm_id;
+ u64 rate;
+};
+
+struct msm8916_icc_desc {
+ struct msm8916_icc_node **nodes;
+ size_t num_nodes;
+};
+
+#define DEFINE_QNODE(_name, _id, _buswidth, _mas_rpm_id, _slv_rpm_id, \
+ ...) \
+ static struct msm8916_icc_node _name = { \
+ .name = #_name, \
+ .id = _id, \
+ .buswidth = _buswidth, \
+ .mas_rpm_id = _mas_rpm_id, \
+ .slv_rpm_id = _slv_rpm_id, \
+ .num_links = ARRAY_SIZE(((int[]){ __VA_ARGS__ })), \
+ .links = { __VA_ARGS__ }, \
+ }
+
+DEFINE_QNODE(bimc_snoc_mas, MSM8916_BIMC_SNOC_MAS, 8, -1, -1, MSM8916_BIMC_SNOC_SLV);
+DEFINE_QNODE(bimc_snoc_slv, MSM8916_BIMC_SNOC_SLV, 8, -1, -1, MSM8916_SNOC_INT_0, MSM8916_SNOC_INT_1);
+DEFINE_QNODE(mas_apss, MSM8916_MASTER_AMPSS_M0, 8, -1, -1, MSM8916_SLAVE_EBI_CH0, MSM8916_BIMC_SNOC_MAS, MSM8916_SLAVE_AMPSS_L2);
+DEFINE_QNODE(mas_audio, MSM8916_MASTER_LPASS, 4, -1, -1, MSM8916_PNOC_MAS_0);
+DEFINE_QNODE(mas_blsp_1, MSM8916_MASTER_BLSP_1, 4, -1, -1, MSM8916_PNOC_MAS_1);
+DEFINE_QNODE(mas_dehr, MSM8916_MASTER_DEHR, 4, -1, -1, MSM8916_PNOC_MAS_0);
+DEFINE_QNODE(mas_gfx, MSM8916_MASTER_GRAPHICS_3D, 8, -1, -1, MSM8916_SLAVE_EBI_CH0, MSM8916_BIMC_SNOC_MAS, MSM8916_SLAVE_AMPSS_L2);
+DEFINE_QNODE(mas_jpeg, MSM8916_MASTER_JPEG, 16, -1, -1, MSM8916_SNOC_MM_INT_0, MSM8916_SNOC_MM_INT_2);
+DEFINE_QNODE(mas_mdp, MSM8916_MASTER_MDP_PORT0, 16, -1, -1, MSM8916_SNOC_MM_INT_0, MSM8916_SNOC_MM_INT_2);
+DEFINE_QNODE(mas_pcnoc_crypto_0, MSM8916_MASTER_CRYPTO_CORE0, 8, -1, -1, MSM8916_PNOC_INT_1);
+DEFINE_QNODE(mas_pcnoc_sdcc_1, MSM8916_MASTER_SDCC_1, 8, -1, -1, MSM8916_PNOC_INT_1);
+DEFINE_QNODE(mas_pcnoc_sdcc_2, MSM8916_MASTER_SDCC_2, 8, -1, -1, MSM8916_PNOC_INT_1);
+DEFINE_QNODE(mas_qdss_bam, MSM8916_MASTER_QDSS_BAM, 8, -1, -1, MSM8916_SNOC_QDSS_INT);
+DEFINE_QNODE(mas_qdss_etr, MSM8916_MASTER_QDSS_ETR, 8, -1, -1, MSM8916_SNOC_QDSS_INT);
+DEFINE_QNODE(mas_snoc_cfg, MSM8916_MASTER_SNOC_CFG, 4, 20, -1, MSM8916_SNOC_QDSS_INT);
+DEFINE_QNODE(mas_spdm, MSM8916_MASTER_SPDM, 4, -1, -1, MSM8916_PNOC_MAS_0);
+DEFINE_QNODE(mas_tcu0, MSM8916_MASTER_TCU0, 8, -1, -1, MSM8916_SLAVE_EBI_CH0, MSM8916_BIMC_SNOC_MAS, MSM8916_SLAVE_AMPSS_L2);
+DEFINE_QNODE(mas_tcu1, MSM8916_MASTER_TCU1, 8, -1, -1, MSM8916_SLAVE_EBI_CH0, MSM8916_BIMC_SNOC_MAS, MSM8916_SLAVE_AMPSS_L2);
+DEFINE_QNODE(mas_usb_hs, MSM8916_MASTER_USB_HS, 4, -1, -1, MSM8916_PNOC_MAS_1);
+DEFINE_QNODE(mas_vfe, MSM8916_MASTER_VFE, 16, -1, -1, MSM8916_SNOC_MM_INT_1, MSM8916_SNOC_MM_INT_2);
+DEFINE_QNODE(mas_video, MSM8916_MASTER_VIDEO_P0, 16, -1, -1, MSM8916_SNOC_MM_INT_0, MSM8916_SNOC_MM_INT_2);
+DEFINE_QNODE(mm_int_0, MSM8916_SNOC_MM_INT_0, 16, -1, -1, MSM8916_SNOC_MM_INT_BIMC);
+DEFINE_QNODE(mm_int_1, MSM8916_SNOC_MM_INT_1, 16, -1, -1, MSM8916_SNOC_MM_INT_BIMC);
+DEFINE_QNODE(mm_int_2, MSM8916_SNOC_MM_INT_2, 16, -1, -1, MSM8916_SNOC_INT_0);
+DEFINE_QNODE(mm_int_bimc, MSM8916_SNOC_MM_INT_BIMC, 16, -1, -1, MSM8916_SNOC_BIMC_1_MAS);
+DEFINE_QNODE(pcnoc_int_0, MSM8916_PNOC_INT_0, 8, -1, -1, MSM8916_PNOC_SNOC_MAS, MSM8916_PNOC_SLV_0, MSM8916_PNOC_SLV_1, MSM8916_PNOC_SLV_2, MSM8916_PNOC_SLV_3, MSM8916_PNOC_SLV_4, MSM8916_PNOC_SLV_8, MSM8916_PNOC_SLV_9);
+DEFINE_QNODE(pcnoc_int_1, MSM8916_PNOC_INT_1, 8, -1, -1, MSM8916_PNOC_SNOC_MAS);
+DEFINE_QNODE(pcnoc_m_0, MSM8916_PNOC_MAS_0, 8, -1, -1, MSM8916_PNOC_INT_0);
+DEFINE_QNODE(pcnoc_m_1, MSM8916_PNOC_MAS_1, 8, -1, -1, MSM8916_PNOC_SNOC_MAS);
+DEFINE_QNODE(pcnoc_s_0, MSM8916_PNOC_SLV_0, 8, -1, -1, MSM8916_SLAVE_CLK_CTL, MSM8916_SLAVE_TLMM, MSM8916_SLAVE_TCSR, MSM8916_SLAVE_SECURITY, MSM8916_SLAVE_MSS);
+DEFINE_QNODE(pcnoc_s_1, MSM8916_PNOC_SLV_1, 8, -1, -1, MSM8916_SLAVE_IMEM_CFG, MSM8916_SLAVE_CRYPTO_0_CFG, MSM8916_SLAVE_MSG_RAM, MSM8916_SLAVE_PDM, MSM8916_SLAVE_PRNG);
+DEFINE_QNODE(pcnoc_s_2, MSM8916_PNOC_SLV_2, 8, -1, -1, MSM8916_SLAVE_SPDM, MSM8916_SLAVE_BOOT_ROM, MSM8916_SLAVE_BIMC_CFG, MSM8916_SLAVE_PNOC_CFG, MSM8916_SLAVE_PMIC_ARB);
+DEFINE_QNODE(pcnoc_s_3, MSM8916_PNOC_SLV_3, 8, -1, -1, MSM8916_SLAVE_MPM, MSM8916_SLAVE_SNOC_CFG, MSM8916_SLAVE_RBCPR_CFG, MSM8916_SLAVE_QDSS_CFG, MSM8916_SLAVE_DEHR_CFG);
+DEFINE_QNODE(pcnoc_s_4, MSM8916_PNOC_SLV_4, 8, -1, -1, MSM8916_SLAVE_VENUS_CFG, MSM8916_SLAVE_CAMERA_CFG, MSM8916_SLAVE_DISPLAY_CFG);
+DEFINE_QNODE(pcnoc_s_8, MSM8916_PNOC_SLV_8, 8, -1, -1, MSM8916_SLAVE_USB_HS, MSM8916_SLAVE_SDCC_1, MSM8916_SLAVE_BLSP_1);
+DEFINE_QNODE(pcnoc_s_9, MSM8916_PNOC_SLV_9, 8, -1, -1, MSM8916_SLAVE_SDCC_2, MSM8916_SLAVE_LPASS, MSM8916_SLAVE_GRAPHICS_3D_CFG);
+DEFINE_QNODE(pcnoc_snoc_mas, MSM8916_PNOC_SNOC_MAS, 8, 29, -1, MSM8916_PNOC_SNOC_SLV);
+DEFINE_QNODE(pcnoc_snoc_slv, MSM8916_PNOC_SNOC_SLV, 8, -1, 45, MSM8916_SNOC_INT_0, MSM8916_SNOC_INT_BIMC, MSM8916_SNOC_INT_1);
+DEFINE_QNODE(qdss_int, MSM8916_SNOC_QDSS_INT, 8, -1, -1, MSM8916_SNOC_INT_0, MSM8916_SNOC_INT_BIMC);
+DEFINE_QNODE(slv_apps_l2, MSM8916_SLAVE_AMPSS_L2, 8, -1, -1, 0);
+DEFINE_QNODE(slv_apss, MSM8916_SLAVE_APSS, 4, -1, 20, 0);
+DEFINE_QNODE(slv_audio, MSM8916_SLAVE_LPASS, 4, -1, -1, 0);
+DEFINE_QNODE(slv_bimc_cfg, MSM8916_SLAVE_BIMC_CFG, 4, -1, -1, 0);
+DEFINE_QNODE(slv_blsp_1, MSM8916_SLAVE_BLSP_1, 4, -1, -1, 0);
+DEFINE_QNODE(slv_boot_rom, MSM8916_SLAVE_BOOT_ROM, 4, -1, -1, 0);
+DEFINE_QNODE(slv_camera_cfg, MSM8916_SLAVE_CAMERA_CFG, 4, -1, -1, 0);
+DEFINE_QNODE(slv_cats_0, MSM8916_SLAVE_CATS_128, 16, -1, 106, 0);
+DEFINE_QNODE(slv_cats_1, MSM8916_SLAVE_OCMEM_64, 8, -1, 107, 0);
+DEFINE_QNODE(slv_clk_ctl, MSM8916_SLAVE_CLK_CTL, 4, -1, -1, 0);
+DEFINE_QNODE(slv_crypto_0_cfg, MSM8916_SLAVE_CRYPTO_0_CFG, 4, -1, -1, 0);
+DEFINE_QNODE(slv_dehr_cfg, MSM8916_SLAVE_DEHR_CFG, 4, -1, -1, 0);
+DEFINE_QNODE(slv_display_cfg, MSM8916_SLAVE_DISPLAY_CFG, 4, -1, -1, 0);
+DEFINE_QNODE(slv_ebi_ch0, MSM8916_SLAVE_EBI_CH0, 8, -1, 0, 0);
+DEFINE_QNODE(slv_gfx_cfg, MSM8916_SLAVE_GRAPHICS_3D_CFG, 4, -1, -1, 0);
+DEFINE_QNODE(slv_imem_cfg, MSM8916_SLAVE_IMEM_CFG, 4, -1, -1, 0);
+DEFINE_QNODE(slv_imem, MSM8916_SLAVE_IMEM, 8, -1, 26, 0);
+DEFINE_QNODE(slv_mpm, MSM8916_SLAVE_MPM, 4, -1, -1, 0);
+DEFINE_QNODE(slv_msg_ram, MSM8916_SLAVE_MSG_RAM, 4, -1, -1, 0);
+DEFINE_QNODE(slv_mss, MSM8916_SLAVE_MSS, 4, -1, -1, 0);
+DEFINE_QNODE(slv_pdm, MSM8916_SLAVE_PDM, 4, -1, -1, 0);
+DEFINE_QNODE(slv_pmic_arb, MSM8916_SLAVE_PMIC_ARB, 4, -1, -1, 0);
+DEFINE_QNODE(slv_pcnoc_cfg, MSM8916_SLAVE_PNOC_CFG, 4, -1, -1, 0);
+DEFINE_QNODE(slv_prng, MSM8916_SLAVE_PRNG, 4, -1, -1, 0);
+DEFINE_QNODE(slv_qdss_cfg, MSM8916_SLAVE_QDSS_CFG, 4, -1, -1, 0);
+DEFINE_QNODE(slv_qdss_stm, MSM8916_SLAVE_QDSS_STM, 4, -1, 30, 0);
+DEFINE_QNODE(slv_rbcpr_cfg, MSM8916_SLAVE_RBCPR_CFG, 4, -1, -1, 0);
+DEFINE_QNODE(slv_sdcc_1, MSM8916_SLAVE_SDCC_1, 4, -1, -1, 0);
+DEFINE_QNODE(slv_sdcc_2, MSM8916_SLAVE_SDCC_2, 4, -1, -1, 0);
+DEFINE_QNODE(slv_security, MSM8916_SLAVE_SECURITY, 4, -1, -1, 0);
+DEFINE_QNODE(slv_snoc_cfg, MSM8916_SLAVE_SNOC_CFG, 4, -1, -1, 0);
+DEFINE_QNODE(slv_spdm, MSM8916_SLAVE_SPDM, 4, -1, -1, 0);
+DEFINE_QNODE(slv_srvc_snoc, MSM8916_SLAVE_SRVC_SNOC, 8, -1, 29, 0);
+DEFINE_QNODE(slv_tcsr, MSM8916_SLAVE_TCSR, 4, -1, -1, 0);
+DEFINE_QNODE(slv_tlmm, MSM8916_SLAVE_TLMM, 4, -1, -1, 0);
+DEFINE_QNODE(slv_usb_hs, MSM8916_SLAVE_USB_HS, 4, -1, -1, 0);
+DEFINE_QNODE(slv_venus_cfg, MSM8916_SLAVE_VENUS_CFG, 4, -1, -1, 0);
+DEFINE_QNODE(snoc_bimc_0_mas, MSM8916_SNOC_BIMC_0_MAS, 8, 3, -1, MSM8916_SNOC_BIMC_0_SLV);
+DEFINE_QNODE(snoc_bimc_0_slv, MSM8916_SNOC_BIMC_0_SLV, 8, -1, 24, MSM8916_SLAVE_EBI_CH0);
+DEFINE_QNODE(snoc_bimc_1_mas, MSM8916_SNOC_BIMC_1_MAS, 16, -1, -1, MSM8916_SNOC_BIMC_1_SLV);
+DEFINE_QNODE(snoc_bimc_1_slv, MSM8916_SNOC_BIMC_1_SLV, 8, -1, -1, MSM8916_SLAVE_EBI_CH0);
+DEFINE_QNODE(snoc_int_0, MSM8916_SNOC_INT_0, 8, 99, 130, MSM8916_SLAVE_QDSS_STM, MSM8916_SLAVE_IMEM, MSM8916_SNOC_PNOC_MAS);
+DEFINE_QNODE(snoc_int_1, MSM8916_SNOC_INT_1, 8, 100, 131, MSM8916_SLAVE_APSS, MSM8916_SLAVE_CATS_128, MSM8916_SLAVE_OCMEM_64);
+DEFINE_QNODE(snoc_int_bimc, MSM8916_SNOC_INT_BIMC, 8, 101, 132, MSM8916_SNOC_BIMC_0_MAS);
+DEFINE_QNODE(snoc_pcnoc_mas, MSM8916_SNOC_PNOC_MAS, 8, -1, -1, MSM8916_SNOC_PNOC_SLV);
+DEFINE_QNODE(snoc_pcnoc_slv, MSM8916_SNOC_PNOC_SLV, 8, -1, -1, MSM8916_PNOC_INT_0);
+
+static struct msm8916_icc_node *msm8916_snoc_nodes[] = {
+ [BIMC_SNOC_SLV] = &bimc_snoc_slv,
+ [MASTER_JPEG] = &mas_jpeg,
+ [MASTER_MDP_PORT0] = &mas_mdp,
+ [MASTER_QDSS_BAM] = &mas_qdss_bam,
+ [MASTER_QDSS_ETR] = &mas_qdss_etr,
+ [MASTER_SNOC_CFG] = &mas_snoc_cfg,
+ [MASTER_VFE] = &mas_vfe,
+ [MASTER_VIDEO_P0] = &mas_video,
+ [SNOC_MM_INT_0] = &mm_int_0,
+ [SNOC_MM_INT_1] = &mm_int_1,
+ [SNOC_MM_INT_2] = &mm_int_2,
+ [SNOC_MM_INT_BIMC] = &mm_int_bimc,
+ [PCNOC_SNOC_SLV] = &pcnoc_snoc_slv,
+ [SLAVE_APSS] = &slv_apss,
+ [SLAVE_CATS_128] = &slv_cats_0,
+ [SLAVE_OCMEM_64] = &slv_cats_1,
+ [SLAVE_IMEM] = &slv_imem,
+ [SLAVE_QDSS_STM] = &slv_qdss_stm,
+ [SLAVE_SRVC_SNOC] = &slv_srvc_snoc,
+ [SNOC_BIMC_0_MAS] = &snoc_bimc_0_mas,
+ [SNOC_BIMC_1_MAS] = &snoc_bimc_1_mas,
+ [SNOC_INT_0] = &snoc_int_0,
+ [SNOC_INT_1] = &snoc_int_1,
+ [SNOC_INT_BIMC] = &snoc_int_bimc,
+ [SNOC_PCNOC_MAS] = &snoc_pcnoc_mas,
+ [SNOC_QDSS_INT] = &qdss_int,
+};
+
+static struct msm8916_icc_desc msm8916_snoc = {
+ .nodes = msm8916_snoc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8916_snoc_nodes),
+};
+
+static struct msm8916_icc_node *msm8916_bimc_nodes[] = {
+ [BIMC_SNOC_MAS] = &bimc_snoc_mas,
+ [MASTER_AMPSS_M0] = &mas_apss,
+ [MASTER_GRAPHICS_3D] = &mas_gfx,
+ [MASTER_TCU0] = &mas_tcu0,
+ [MASTER_TCU1] = &mas_tcu1,
+ [SLAVE_AMPSS_L2] = &slv_apps_l2,
+ [SLAVE_EBI_CH0] = &slv_ebi_ch0,
+ [SNOC_BIMC_0_SLV] = &snoc_bimc_0_slv,
+ [SNOC_BIMC_1_SLV] = &snoc_bimc_1_slv,
+};
+
+static struct msm8916_icc_desc msm8916_bimc = {
+ .nodes = msm8916_bimc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8916_bimc_nodes),
+};
+
+static struct msm8916_icc_node *msm8916_pcnoc_nodes[] = {
+ [MASTER_BLSP_1] = &mas_blsp_1,
+ [MASTER_DEHR] = &mas_dehr,
+ [MASTER_LPASS] = &mas_audio,
+ [MASTER_CRYPTO_CORE0] = &mas_pcnoc_crypto_0,
+ [MASTER_SDCC_1] = &mas_pcnoc_sdcc_1,
+ [MASTER_SDCC_2] = &mas_pcnoc_sdcc_2,
+ [MASTER_SPDM] = &mas_spdm,
+ [MASTER_USB_HS] = &mas_usb_hs,
+ [PCNOC_INT_0] = &pcnoc_int_0,
+ [PCNOC_INT_1] = &pcnoc_int_1,
+ [PCNOC_MAS_0] = &pcnoc_m_0,
+ [PCNOC_MAS_1] = &pcnoc_m_1,
+ [PCNOC_SLV_0] = &pcnoc_s_0,
+ [PCNOC_SLV_1] = &pcnoc_s_1,
+ [PCNOC_SLV_2] = &pcnoc_s_2,
+ [PCNOC_SLV_3] = &pcnoc_s_3,
+ [PCNOC_SLV_4] = &pcnoc_s_4,
+ [PCNOC_SLV_8] = &pcnoc_s_8,
+ [PCNOC_SLV_9] = &pcnoc_s_9,
+ [PCNOC_SNOC_MAS] = &pcnoc_snoc_mas,
+ [SLAVE_BIMC_CFG] = &slv_bimc_cfg,
+ [SLAVE_BLSP_1] = &slv_blsp_1,
+ [SLAVE_BOOT_ROM] = &slv_boot_rom,
+ [SLAVE_CAMERA_CFG] = &slv_camera_cfg,
+ [SLAVE_CLK_CTL] = &slv_clk_ctl,
+ [SLAVE_CRYPTO_0_CFG] = &slv_crypto_0_cfg,
+ [SLAVE_DEHR_CFG] = &slv_dehr_cfg,
+ [SLAVE_DISPLAY_CFG] = &slv_display_cfg,
+ [SLAVE_GRAPHICS_3D_CFG] = &slv_gfx_cfg,
+ [SLAVE_IMEM_CFG] = &slv_imem_cfg,
+ [SLAVE_LPASS] = &slv_audio,
+ [SLAVE_MPM] = &slv_mpm,
+ [SLAVE_MSG_RAM] = &slv_msg_ram,
+ [SLAVE_MSS] = &slv_mss,
+ [SLAVE_PDM] = &slv_pdm,
+ [SLAVE_PMIC_ARB] = &slv_pmic_arb,
+ [SLAVE_PCNOC_CFG] = &slv_pcnoc_cfg,
+ [SLAVE_PRNG] = &slv_prng,
+ [SLAVE_QDSS_CFG] = &slv_qdss_cfg,
+ [SLAVE_RBCPR_CFG] = &slv_rbcpr_cfg,
+ [SLAVE_SDCC_1] = &slv_sdcc_1,
+ [SLAVE_SDCC_2] = &slv_sdcc_2,
+ [SLAVE_SECURITY] = &slv_security,
+ [SLAVE_SNOC_CFG] = &slv_snoc_cfg,
+ [SLAVE_SPDM] = &slv_spdm,
+ [SLAVE_TCSR] = &slv_tcsr,
+ [SLAVE_TLMM] = &slv_tlmm,
+ [SLAVE_USB_HS] = &slv_usb_hs,
+ [SLAVE_VENUS_CFG] = &slv_venus_cfg,
+ [SNOC_PCNOC_SLV] = &snoc_pcnoc_slv,
+};
+
+static struct msm8916_icc_desc msm8916_pcnoc = {
+ .nodes = msm8916_pcnoc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8916_pcnoc_nodes),
+};
+
+static int msm8916_icc_set(struct icc_node *src, struct icc_node *dst)
+{
+ struct msm8916_icc_provider *qp;
+ struct msm8916_icc_node *qn;
+ u64 sum_bw, max_peak_bw, rate;
+ u32 agg_avg = 0, agg_peak = 0;
+ struct icc_provider *provider;
+ struct icc_node *n;
+ int ret, i;
+
+ qn = src->data;
+ provider = src->provider;
+ qp = to_msm8916_provider(provider);
+
+ list_for_each_entry(n, &provider->nodes, node_list)
+ provider->aggregate(n, 0, n->avg_bw, n->peak_bw,
+ &agg_avg, &agg_peak);
+
+ sum_bw = icc_units_to_bps(agg_avg);
+ max_peak_bw = icc_units_to_bps(agg_peak);
+
+ /* send bandwidth request message to the RPM processor */
+ if (qn->mas_rpm_id != -1) {
+ ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
+ RPM_BUS_MASTER_REQ,
+ qn->mas_rpm_id,
+ sum_bw);
+ if (ret) {
+ pr_err("qcom_icc_rpm_smd_send mas %d error %d\n",
+ qn->mas_rpm_id, ret);
+ return ret;
+ }
+ }
+
+ if (qn->slv_rpm_id != -1) {
+ ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
+ RPM_BUS_SLAVE_REQ,
+ qn->slv_rpm_id,
+ sum_bw);
+ if (ret) {
+ pr_err("qcom_icc_rpm_smd_send slv error %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ rate = max(sum_bw, max_peak_bw);
+
+ do_div(rate, qn->buswidth);
+
+ if (qn->rate == rate)
+ return 0;
+
+ for (i = 0; i < qp->num_clks; i++) {
+ ret = clk_set_rate(qp->bus_clks[i].clk, rate);
+ if (ret) {
+ pr_err("%s clk_set_rate error: %d\n",
+ qp->bus_clks[i].id, ret);
+ return ret;
+ }
+ }
+
+ qn->rate = rate;
+
+ return 0;
+}
+
+static int msm8916_qnoc_probe(struct platform_device *pdev)
+{
+ const struct msm8916_icc_desc *desc;
+ struct msm8916_icc_node **qnodes;
+ struct msm8916_icc_provider *qp;
+ struct device *dev = &pdev->dev;
+ struct icc_onecell_data *data;
+ struct icc_provider *provider;
+ struct icc_node *node;
+ size_t num_nodes, i;
+ int ret;
+
+ /* wait for the RPM proxy */
+ if (!qcom_icc_rpm_smd_available())
+ return -EPROBE_DEFER;
+
+ desc = of_device_get_match_data(dev);
+ if (!desc)
+ return -EINVAL;
+
+ qnodes = desc->nodes;
+ num_nodes = desc->num_nodes;
+
+ qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL);
+ if (!qp)
+ return -ENOMEM;
+
+ data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ qp->bus_clks = devm_kmemdup(dev, msm8916_bus_clocks,
+ sizeof(msm8916_bus_clocks), GFP_KERNEL);
+ if (!qp->bus_clks)
+ return -ENOMEM;
+
+ qp->num_clks = ARRAY_SIZE(msm8916_bus_clocks);
+ ret = devm_clk_bulk_get(dev, qp->num_clks, qp->bus_clks);
+ if (ret)
+ return ret;
+
+ ret = clk_bulk_prepare_enable(qp->num_clks, qp->bus_clks);
+ if (ret)
+ return ret;
+
+ provider = &qp->provider;
+ INIT_LIST_HEAD(&provider->nodes);
+ provider->dev = dev;
+ provider->set = msm8916_icc_set;
+ provider->aggregate = icc_std_aggregate;
+ provider->xlate = of_icc_xlate_onecell;
+ provider->data = data;
+
+ ret = icc_provider_add(provider);
+ if (ret) {
+ dev_err(dev, "error adding interconnect provider: %d\n", ret);
+ clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
+ return ret;
+ }
+
+ for (i = 0; i < num_nodes; i++) {
+ size_t j;
+
+ node = icc_node_create(qnodes[i]->id);
+ if (IS_ERR(node)) {
+ ret = PTR_ERR(node);
+ goto err;
+ }
+
+ node->name = qnodes[i]->name;
+ node->data = qnodes[i];
+ icc_node_add(node, provider);
+
+ for (j = 0; j < qnodes[i]->num_links; j++)
+ icc_link_create(node, qnodes[i]->links[j]);
+
+ data->nodes[i] = node;
+ }
+ data->num_nodes = num_nodes;
+
+ platform_set_drvdata(pdev, qp);
+
+ return 0;
+
+err:
+ icc_nodes_remove(provider);
+ icc_provider_del(provider);
+ clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
+
+ return ret;
+}
+
+static int msm8916_qnoc_remove(struct platform_device *pdev)
+{
+ struct msm8916_icc_provider *qp = platform_get_drvdata(pdev);
+
+ icc_nodes_remove(&qp->provider);
+ clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
+ return icc_provider_del(&qp->provider);
+}
+
+static const struct of_device_id msm8916_noc_of_match[] = {
+ { .compatible = "qcom,msm8916-bimc", .data = &msm8916_bimc },
+ { .compatible = "qcom,msm8916-pcnoc", .data = &msm8916_pcnoc },
+ { .compatible = "qcom,msm8916-snoc", .data = &msm8916_snoc },
+ { }
+};
+MODULE_DEVICE_TABLE(of, msm8916_noc_of_match);
+
+static struct platform_driver msm8916_noc_driver = {
+ .probe = msm8916_qnoc_probe,
+ .remove = msm8916_qnoc_remove,
+ .driver = {
+ .name = "qnoc-msm8916",
+ .of_match_table = msm8916_noc_of_match,
+ },
+};
+module_platform_driver(msm8916_noc_driver);
+MODULE_AUTHOR("Georgi Djakov <georgi.djakov@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm MSM8916 NoC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/interconnect/qcom/msm8974.c b/drivers/interconnect/qcom/msm8974.c
index bf8bd1aee358..3a313e11e73d 100644
--- a/drivers/interconnect/qcom/msm8974.c
+++ b/drivers/interconnect/qcom/msm8974.c
@@ -550,15 +550,6 @@ static struct msm8974_icc_desc msm8974_snoc = {
.num_nodes = ARRAY_SIZE(msm8974_snoc_nodes),
};
-static int msm8974_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
- u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
-{
- *agg_avg += avg_bw;
- *agg_peak = max(*agg_peak, peak_bw);
-
- return 0;
-}
-
static void msm8974_icc_rpm_smd_send(struct device *dev, int rsc_type,
char *name, int id, u64 val)
{
@@ -603,8 +594,8 @@ static int msm8974_icc_set(struct icc_node *src, struct icc_node *dst)
qp = to_msm8974_icc_provider(provider);
list_for_each_entry(n, &provider->nodes, node_list)
- msm8974_icc_aggregate(n, 0, n->avg_bw, n->peak_bw,
- &agg_avg, &agg_peak);
+ provider->aggregate(n, 0, n->avg_bw, n->peak_bw,
+ &agg_avg, &agg_peak);
sum_bw = icc_units_to_bps(agg_avg);
max_peak_bw = icc_units_to_bps(agg_peak);
@@ -652,7 +643,7 @@ static int msm8974_icc_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct icc_onecell_data *data;
struct icc_provider *provider;
- struct icc_node *node, *tmp;
+ struct icc_node *node;
size_t num_nodes, i;
int ret;
@@ -694,7 +685,7 @@ static int msm8974_icc_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&provider->nodes);
provider->dev = dev;
provider->set = msm8974_icc_set;
- provider->aggregate = msm8974_icc_aggregate;
+ provider->aggregate = icc_std_aggregate;
provider->xlate = of_icc_xlate_onecell;
provider->data = data;
@@ -732,10 +723,7 @@ static int msm8974_icc_probe(struct platform_device *pdev)
return 0;
err_del_icc:
- list_for_each_entry_safe(node, tmp, &provider->nodes, node_list) {
- icc_node_del(node);
- icc_node_destroy(node->id);
- }
+ icc_nodes_remove(provider);
icc_provider_del(provider);
err_disable_clks:
@@ -747,16 +735,10 @@ err_disable_clks:
static int msm8974_icc_remove(struct platform_device *pdev)
{
struct msm8974_icc_provider *qp = platform_get_drvdata(pdev);
- struct icc_provider *provider = &qp->provider;
- struct icc_node *n, *tmp;
- list_for_each_entry_safe(n, tmp, &provider->nodes, node_list) {
- icc_node_del(n);
- icc_node_destroy(n->id);
- }
+ icc_nodes_remove(&qp->provider);
clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
-
- return icc_provider_del(provider);
+ return icc_provider_del(&qp->provider);
}
static const struct of_device_id msm8974_noc_of_match[] = {
diff --git a/drivers/interconnect/qcom/qcs404.c b/drivers/interconnect/qcom/qcs404.c
index 8e0735a87040..d4769a5ea182 100644
--- a/drivers/interconnect/qcom/qcs404.c
+++ b/drivers/interconnect/qcom/qcs404.c
@@ -327,15 +327,6 @@ static struct qcom_icc_desc qcs404_snoc = {
.num_nodes = ARRAY_SIZE(qcs404_snoc_nodes),
};
-static int qcom_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
- u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
-{
- *agg_avg += avg_bw;
- *agg_peak = max(*agg_peak, peak_bw);
-
- return 0;
-}
-
static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
{
struct qcom_icc_provider *qp;
@@ -354,8 +345,8 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
qp = to_qcom_provider(provider);
list_for_each_entry(n, &provider->nodes, node_list)
- qcom_icc_aggregate(n, 0, n->avg_bw, n->peak_bw,
- &agg_avg, &agg_peak);
+ provider->aggregate(n, 0, n->avg_bw, n->peak_bw,
+ &agg_avg, &agg_peak);
sum_bw = icc_units_to_bps(agg_avg);
max_peak_bw = icc_units_to_bps(agg_peak);
@@ -414,7 +405,7 @@ static int qnoc_probe(struct platform_device *pdev)
struct icc_provider *provider;
struct qcom_icc_node **qnodes;
struct qcom_icc_provider *qp;
- struct icc_node *node, *tmp;
+ struct icc_node *node;
size_t num_nodes, i;
int ret;
@@ -456,7 +447,7 @@ static int qnoc_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&provider->nodes);
provider->dev = dev;
provider->set = qcom_icc_set;
- provider->aggregate = qcom_icc_aggregate;
+ provider->aggregate = icc_std_aggregate;
provider->xlate = of_icc_xlate_onecell;
provider->data = data;
@@ -494,10 +485,7 @@ static int qnoc_probe(struct platform_device *pdev)
return 0;
err:
- list_for_each_entry_safe(node, tmp, &provider->nodes, node_list) {
- icc_node_del(node);
- icc_node_destroy(node->id);
- }
+ icc_nodes_remove(provider);
clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
icc_provider_del(provider);
@@ -507,16 +495,10 @@ err:
static int qnoc_remove(struct platform_device *pdev)
{
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
- struct icc_provider *provider = &qp->provider;
- struct icc_node *n, *tmp;
- list_for_each_entry_safe(n, tmp, &provider->nodes, node_list) {
- icc_node_del(n);
- icc_node_destroy(n->id);
- }
+ icc_nodes_remove(&qp->provider);
clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
-
- return icc_provider_del(provider);
+ return icc_provider_del(&qp->provider);
}
static const struct of_device_id qcs404_noc_of_match[] = {
diff --git a/drivers/interconnect/qcom/sdm845.c b/drivers/interconnect/qcom/sdm845.c
index 387267ee9648..f078cf0fce56 100644
--- a/drivers/interconnect/qcom/sdm845.c
+++ b/drivers/interconnect/qcom/sdm845.c
@@ -855,11 +855,7 @@ static int qnoc_probe(struct platform_device *pdev)
return ret;
err:
- list_for_each_entry(node, &provider->nodes, node_list) {
- icc_node_del(node);
- icc_node_destroy(node->id);
- }
-
+ icc_nodes_remove(provider);
icc_provider_del(provider);
return ret;
}
@@ -867,15 +863,9 @@ err:
static int qnoc_remove(struct platform_device *pdev)
{
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
- struct icc_provider *provider = &qp->provider;
- struct icc_node *n, *tmp;
-
- list_for_each_entry_safe(n, tmp, &provider->nodes, node_list) {
- icc_node_del(n);
- icc_node_destroy(n->id);
- }
- return icc_provider_del(provider);
+ icc_nodes_remove(&qp->provider);
+ return icc_provider_del(&qp->provider);
}
static const struct of_device_id qnoc_of_match[] = {
diff --git a/drivers/interconnect/trace.h b/drivers/interconnect/trace.h
new file mode 100644
index 000000000000..3d668ff566bf
--- /dev/null
+++ b/drivers/interconnect/trace.h
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Interconnect framework tracepoints
+ * Copyright (c) 2019, Linaro Ltd.
+ * Author: Georgi Djakov <georgi.djakov@linaro.org>
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM interconnect
+
+#if !defined(_TRACE_INTERCONNECT_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_INTERCONNECT_H
+
+#include <linux/interconnect.h>
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(icc_set_bw,
+
+ TP_PROTO(struct icc_path *p, struct icc_node *n, int i,
+ u32 avg_bw, u32 peak_bw),
+
+ TP_ARGS(p, n, i, avg_bw, peak_bw),
+
+ TP_STRUCT__entry(
+ __string(path_name, p->name)
+ __string(dev, dev_name(p->reqs[i].dev))
+ __string(node_name, n->name)
+ __field(u32, avg_bw)
+ __field(u32, peak_bw)
+ __field(u32, node_avg_bw)
+ __field(u32, node_peak_bw)
+ ),
+
+ TP_fast_assign(
+ __assign_str(path_name, p->name);
+ __assign_str(dev, dev_name(p->reqs[i].dev));
+ __assign_str(node_name, n->name);
+ __entry->avg_bw = avg_bw;
+ __entry->peak_bw = peak_bw;
+ __entry->node_avg_bw = n->avg_bw;
+ __entry->node_peak_bw = n->peak_bw;
+ ),
+
+ TP_printk("path=%s dev=%s node=%s avg_bw=%u peak_bw=%u agg_avg=%u agg_peak=%u",
+ __get_str(path_name),
+ __get_str(dev),
+ __get_str(node_name),
+ __entry->avg_bw,
+ __entry->peak_bw,
+ __entry->node_avg_bw,
+ __entry->node_peak_bw)
+);
+
+TRACE_EVENT(icc_set_bw_end,
+
+ TP_PROTO(struct icc_path *p, int ret),
+
+ TP_ARGS(p, ret),
+
+ TP_STRUCT__entry(
+ __string(path_name, p->name)
+ __string(dev, dev_name(p->reqs[0].dev))
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ __assign_str(path_name, p->name);
+ __assign_str(dev, dev_name(p->reqs[0].dev));
+ __entry->ret = ret;
+ ),
+
+ TP_printk("path=%s dev=%s ret=%d",
+ __get_str(path_name),
+ __get_str(dev),
+ __entry->ret)
+);
+
+#endif /* _TRACE_INTERCONNECT_H */
+
+/* This part must be outside protection */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+#include <trace/define_trace.h>
diff --git a/drivers/misc/cardreader/alcor_pci.c b/drivers/misc/cardreader/alcor_pci.c
index 259fe1dfec03..cd402c89189e 100644
--- a/drivers/misc/cardreader/alcor_pci.c
+++ b/drivers/misc/cardreader/alcor_pci.c
@@ -38,12 +38,18 @@ static const struct alcor_dev_cfg au6621_cfg = {
.dma = 1,
};
+static const struct alcor_dev_cfg au6625_cfg = {
+ .dma = 0,
+};
+
static const struct pci_device_id pci_ids[] = {
{ PCI_DEVICE(PCI_ID_ALCOR_MICRO, PCI_ID_AU6601),
.driver_data = (kernel_ulong_t)&alcor_cfg },
{ PCI_DEVICE(PCI_ID_ALCOR_MICRO, PCI_ID_AU6621),
.driver_data = (kernel_ulong_t)&au6621_cfg },
- { },
+ { PCI_DEVICE(PCI_ID_ALCOR_MICRO, PCI_ID_AU6625),
+ .driver_data = (kernel_ulong_t)&au6625_cfg },
+ {},
};
MODULE_DEVICE_TABLE(pci, pci_ids);
diff --git a/drivers/misc/cardreader/rts5261.c b/drivers/misc/cardreader/rts5261.c
index 32dcec2e9dfd..bc4967a6efa1 100644
--- a/drivers/misc/cardreader/rts5261.c
+++ b/drivers/misc/cardreader/rts5261.c
@@ -628,7 +628,8 @@ int rts5261_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk)
{
int err, clk;
- u8 n, clk_divider, mcu_cnt, div;
+ u16 n;
+ u8 clk_divider, mcu_cnt, div;
static const u8 depth[] = {
[RTSX_SSC_DEPTH_4M] = RTS5261_SSC_DEPTH_4M,
[RTSX_SSC_DEPTH_2M] = RTS5261_SSC_DEPTH_2M,
@@ -661,13 +662,13 @@ int rts5261_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
return 0;
if (pcr->ops->conv_clk_and_div_n)
- n = (u8)pcr->ops->conv_clk_and_div_n(clk, CLK_TO_DIV_N);
+ n = pcr->ops->conv_clk_and_div_n(clk, CLK_TO_DIV_N);
else
- n = (u8)(clk - 4);
+ n = clk - 4;
if ((clk <= 4) || (n > 396))
return -EINVAL;
- mcu_cnt = (u8)(125/clk + 3);
+ mcu_cnt = 125/clk + 3;
if (mcu_cnt > 15)
mcu_cnt = 15;
@@ -676,7 +677,7 @@ int rts5261_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
if (pcr->ops->conv_clk_and_div_n) {
int dbl_clk = pcr->ops->conv_clk_and_div_n(n,
DIV_N_TO_CLK) * 2;
- n = (u8)pcr->ops->conv_clk_and_div_n(dbl_clk,
+ n = pcr->ops->conv_clk_and_div_n(dbl_clk,
CLK_TO_DIV_N);
} else {
n = (n + 4) * 2 - 4;
diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c
index aed9c445d1e2..fb2eff69e449 100644
--- a/drivers/misc/cxl/context.c
+++ b/drivers/misc/cxl/context.c
@@ -352,7 +352,7 @@ void cxl_context_free(struct cxl_context *ctx)
void cxl_context_mm_count_get(struct cxl_context *ctx)
{
if (ctx->mm)
- atomic_inc(&ctx->mm->mm_count);
+ mmgrab(ctx->mm);
}
void cxl_context_mm_count_put(struct cxl_context *ctx)
diff --git a/drivers/misc/genwqe/card_ddcb.c b/drivers/misc/genwqe/card_ddcb.c
index 026c6ca24540..905106579935 100644
--- a/drivers/misc/genwqe/card_ddcb.c
+++ b/drivers/misc/genwqe/card_ddcb.c
@@ -1084,7 +1084,7 @@ static int setup_ddcb_queue(struct genwqe_dev *cd, struct ddcb_queue *queue)
queue->ddcb_daddr);
queue->ddcb_vaddr = NULL;
queue->ddcb_daddr = 0ull;
- return -ENODEV;
+ return rc;
}
@@ -1179,7 +1179,7 @@ static irqreturn_t genwqe_vf_isr(int irq, void *dev_id)
*/
static int genwqe_card_thread(void *data)
{
- int should_stop = 0, rc = 0;
+ int should_stop = 0;
struct genwqe_dev *cd = (struct genwqe_dev *)data;
while (!kthread_should_stop()) {
@@ -1187,12 +1187,12 @@ static int genwqe_card_thread(void *data)
genwqe_check_ddcb_queue(cd, &cd->queue);
if (GENWQE_POLLING_ENABLED) {
- rc = wait_event_interruptible_timeout(
+ wait_event_interruptible_timeout(
cd->queue_waitq,
genwqe_ddcbs_in_flight(cd) ||
(should_stop = kthread_should_stop()), 1);
} else {
- rc = wait_event_interruptible_timeout(
+ wait_event_interruptible_timeout(
cd->queue_waitq,
genwqe_next_ddcb_ready(cd) ||
(should_stop = kthread_should_stop()), HZ);
diff --git a/drivers/misc/isl29020.c b/drivers/misc/isl29020.c
index b6125620eb8f..fc5ff2805b94 100644
--- a/drivers/misc/isl29020.c
+++ b/drivers/misc/isl29020.c
@@ -173,6 +173,7 @@ static int isl29020_probe(struct i2c_client *client,
static int isl29020_remove(struct i2c_client *client)
{
+ pm_runtime_disable(&client->dev);
sysfs_remove_group(&client->dev.kobj, &m_als_gr);
return 0;
}
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index a0a495c95e3c..8d468e0a950a 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -765,7 +765,7 @@ static ssize_t uuid_show(struct device *dev, struct device_attribute *a,
struct mei_cl_device *cldev = to_mei_cl_device(dev);
const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl);
- return scnprintf(buf, PAGE_SIZE, "%pUl", uuid);
+ return sprintf(buf, "%pUl", uuid);
}
static DEVICE_ATTR_RO(uuid);
@@ -775,7 +775,7 @@ static ssize_t version_show(struct device *dev, struct device_attribute *a,
struct mei_cl_device *cldev = to_mei_cl_device(dev);
u8 version = mei_me_cl_ver(cldev->me_cl);
- return scnprintf(buf, PAGE_SIZE, "%02X", version);
+ return sprintf(buf, "%02X", version);
}
static DEVICE_ATTR_RO(version);
@@ -797,7 +797,7 @@ static ssize_t max_conn_show(struct device *dev, struct device_attribute *a,
struct mei_cl_device *cldev = to_mei_cl_device(dev);
u8 maxconn = mei_me_cl_max_conn(cldev->me_cl);
- return scnprintf(buf, PAGE_SIZE, "%d", maxconn);
+ return sprintf(buf, "%d", maxconn);
}
static DEVICE_ATTR_RO(max_conn);
@@ -807,7 +807,7 @@ static ssize_t fixed_show(struct device *dev, struct device_attribute *a,
struct mei_cl_device *cldev = to_mei_cl_device(dev);
u8 fixed = mei_me_cl_fixed(cldev->me_cl);
- return scnprintf(buf, PAGE_SIZE, "%d", fixed);
+ return sprintf(buf, "%d", fixed);
}
static DEVICE_ATTR_RO(fixed);
@@ -817,7 +817,7 @@ static ssize_t max_len_show(struct device *dev, struct device_attribute *a,
struct mei_cl_device *cldev = to_mei_cl_device(dev);
u32 maxlen = mei_me_cl_max_len(cldev->me_cl);
- return scnprintf(buf, PAGE_SIZE, "%u", maxlen);
+ return sprintf(buf, "%u", maxlen);
}
static DEVICE_ATTR_RO(max_len);
diff --git a/drivers/misc/mei/hdcp/mei_hdcp.c b/drivers/misc/mei/hdcp/mei_hdcp.c
index 93027fd96c71..4c596c646ac0 100644
--- a/drivers/misc/mei/hdcp/mei_hdcp.c
+++ b/drivers/misc/mei/hdcp/mei_hdcp.c
@@ -757,11 +757,38 @@ static const struct component_master_ops mei_component_master_ops = {
.unbind = mei_component_master_unbind,
};
+/**
+ * mei_hdcp_component_match - compare function for matching mei hdcp.
+ *
+ * The function checks if the driver is i915, the subcomponent is HDCP
+ * and the grand parent of hdcp and the parent of i915 are the same
+ * PCH device.
+ *
+ * @dev: master device
+ * @subcomponent: subcomponent to match (I915_COMPONENT_HDCP)
+ * @data: compare data (mei hdcp device)
+ *
+ * Return:
+ * * 1 - if components match
+ * * 0 - otherwise
+ */
static int mei_hdcp_component_match(struct device *dev, int subcomponent,
void *data)
{
- return !strcmp(dev->driver->name, "i915") &&
- subcomponent == I915_COMPONENT_HDCP;
+ struct device *base = data;
+
+ if (strcmp(dev->driver->name, "i915") ||
+ subcomponent != I915_COMPONENT_HDCP)
+ return 0;
+
+ base = base->parent;
+ if (!base)
+ return 0;
+
+ base = base->parent;
+ dev = dev->parent;
+
+ return (base && dev && dev == base);
}
static int mei_hdcp_probe(struct mei_cl_device *cldev,
@@ -785,7 +812,7 @@ static int mei_hdcp_probe(struct mei_cl_device *cldev,
master_match = NULL;
component_match_add_typed(&cldev->dev, &master_match,
- mei_hdcp_component_match, comp_master);
+ mei_hdcp_component_match, &cldev->dev);
if (IS_ERR_OR_NULL(master_match)) {
ret = -ENOMEM;
goto err_exit;
diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h
index 7cd67fb2365d..87a0201ba6b3 100644
--- a/drivers/misc/mei/hw-me-regs.h
+++ b/drivers/misc/mei/hw-me-regs.h
@@ -81,10 +81,16 @@
#define MEI_DEV_ID_CMP_LP 0x02e0 /* Comet Point LP */
#define MEI_DEV_ID_CMP_LP_3 0x02e4 /* Comet Point LP 3 (iTouch) */
+
#define MEI_DEV_ID_CMP_V 0xA3BA /* Comet Point Lake V */
+#define MEI_DEV_ID_CMP_H 0x06e0 /* Comet Lake H */
+#define MEI_DEV_ID_CMP_H_3 0x06e4 /* Comet Lake H 3 (iTouch) */
+
#define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */
+#define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */
+
#define MEI_DEV_ID_TGP_LP 0xA0E0 /* Tiger Lake Point LP */
#define MEI_DEV_ID_MCC 0x4B70 /* Mule Creek Canyon (EHL) */
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
index c845b7e40f26..2711451b3d87 100644
--- a/drivers/misc/mei/pci-me.c
+++ b/drivers/misc/mei/pci-me.c
@@ -99,11 +99,15 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
{MEI_PCI_DEVICE(MEI_DEV_ID_CMP_LP, MEI_ME_PCH12_CFG)},
{MEI_PCI_DEVICE(MEI_DEV_ID_CMP_LP_3, MEI_ME_PCH8_CFG)},
{MEI_PCI_DEVICE(MEI_DEV_ID_CMP_V, MEI_ME_PCH12_CFG)},
+ {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H, MEI_ME_PCH12_CFG)},
+ {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_CFG)},
{MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)},
{MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)},
+ {MEI_PCI_DEVICE(MEI_DEV_ID_JSP_N, MEI_ME_PCH15_CFG)},
+
{MEI_PCI_DEVICE(MEI_DEV_ID_MCC, MEI_ME_PCH15_CFG)},
{MEI_PCI_DEVICE(MEI_DEV_ID_MCC_4, MEI_ME_PCH8_CFG)},
diff --git a/drivers/misc/mic/card/mic_debugfs.c b/drivers/misc/mic/card/mic_debugfs.c
index 3ee3d2402634..b58608829b18 100644
--- a/drivers/misc/mic/card/mic_debugfs.c
+++ b/drivers/misc/mic/card/mic_debugfs.c
@@ -65,9 +65,6 @@ void __init mic_create_card_debug_dir(struct mic_driver *mdrv)
*/
void mic_delete_card_debug_dir(struct mic_driver *mdrv)
{
- if (!mdrv->dbg_dir)
- return;
-
debugfs_remove_recursive(mdrv->dbg_dir);
}
diff --git a/drivers/misc/mic/cosm/cosm_debugfs.c b/drivers/misc/mic/cosm/cosm_debugfs.c
index 2fc9f4bf7001..68a731fd86de 100644
--- a/drivers/misc/mic/cosm/cosm_debugfs.c
+++ b/drivers/misc/mic/cosm/cosm_debugfs.c
@@ -102,9 +102,6 @@ void cosm_create_debug_dir(struct cosm_device *cdev)
void cosm_delete_debug_dir(struct cosm_device *cdev)
{
- if (!cdev->dbg_dir)
- return;
-
debugfs_remove_recursive(cdev->dbg_dir);
}
diff --git a/drivers/misc/mic/host/mic_debugfs.c b/drivers/misc/mic/host/mic_debugfs.c
index 8a8e41677501..ab0db7a2ac8c 100644
--- a/drivers/misc/mic/host/mic_debugfs.c
+++ b/drivers/misc/mic/host/mic_debugfs.c
@@ -129,9 +129,6 @@ void mic_create_debug_dir(struct mic_device *mdev)
*/
void mic_delete_debug_dir(struct mic_device *mdev)
{
- if (!mdev->dbg_dir)
- return;
-
debugfs_remove_recursive(mdev->dbg_dir);
}
diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c
index 063e4419cd7e..b7f510676cd6 100644
--- a/drivers/misc/pti.c
+++ b/drivers/misc/pti.c
@@ -792,7 +792,7 @@ static int pti_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
unsigned int a;
- int retval = -EINVAL;
+ int retval;
int pci_bar = 1;
dev_dbg(&pdev->dev, "%s %s(%d): PTI PCI ID %04x:%04x\n", __FILE__,
@@ -910,7 +910,7 @@ static struct pci_driver pti_pci_driver = {
*/
static int __init pti_init(void)
{
- int retval = -EINVAL;
+ int retval;
/* First register module as tty device */
diff --git a/drivers/misc/pvpanic.c b/drivers/misc/pvpanic.c
index 95ff7c5a1dfb..a6e1a8983e1f 100644
--- a/drivers/misc/pvpanic.c
+++ b/drivers/misc/pvpanic.c
@@ -10,16 +10,16 @@
#include <linux/acpi.h>
#include <linux/kernel.h>
+#include <linux/kexec.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/types.h>
+#include <uapi/misc/pvpanic.h>
static void __iomem *base;
-#define PVPANIC_PANICKED (1 << 0)
-
MODULE_AUTHOR("Hu Tao <hutao@cn.fujitsu.com>");
MODULE_DESCRIPTION("pvpanic device driver");
MODULE_LICENSE("GPL");
@@ -34,7 +34,13 @@ static int
pvpanic_panic_notify(struct notifier_block *nb, unsigned long code,
void *unused)
{
- pvpanic_send_event(PVPANIC_PANICKED);
+ unsigned int event = PVPANIC_PANICKED;
+
+ if (kexec_crash_loaded())
+ event = PVPANIC_CRASH_LOADED;
+
+ pvpanic_send_event(event);
+
return NOTIFY_DONE;
}
diff --git a/drivers/misc/sram-exec.c b/drivers/misc/sram-exec.c
index d054e2842a5f..cb57ac6ab4c3 100644
--- a/drivers/misc/sram-exec.c
+++ b/drivers/misc/sram-exec.c
@@ -85,6 +85,7 @@ void *sram_exec_copy(struct gen_pool *pool, void *dst, void *src,
unsigned long base;
int pages;
void *dst_cpy;
+ int ret;
mutex_lock(&exec_pool_list_mutex);
list_for_each_entry(p, &exec_pool_list, list) {
@@ -104,16 +105,28 @@ void *sram_exec_copy(struct gen_pool *pool, void *dst, void *src,
mutex_lock(&part->lock);
- set_memory_nx((unsigned long)base, pages);
- set_memory_rw((unsigned long)base, pages);
+ ret = set_memory_nx((unsigned long)base, pages);
+ if (ret)
+ goto error_out;
+ ret = set_memory_rw((unsigned long)base, pages);
+ if (ret)
+ goto error_out;
dst_cpy = fncpy(dst, src, size);
- set_memory_ro((unsigned long)base, pages);
- set_memory_x((unsigned long)base, pages);
+ ret = set_memory_ro((unsigned long)base, pages);
+ if (ret)
+ goto error_out;
+ ret = set_memory_x((unsigned long)base, pages);
+ if (ret)
+ goto error_out;
mutex_unlock(&part->lock);
return dst_cpy;
+
+error_out:
+ mutex_unlock(&part->lock);
+ return NULL;
}
EXPORT_SYMBOL_GPL(sram_exec_copy);
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index 2ae9948a91e1..14136d2cc8f9 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -736,8 +736,8 @@ static int st_tty_open(struct tty_struct *tty)
static void st_tty_close(struct tty_struct *tty)
{
- unsigned char i = ST_MAX_CHANNELS;
- unsigned long flags = 0;
+ unsigned char i;
+ unsigned long flags;
struct st_data_s *st_gdata = tty->disc_data;
pr_info("%s ", __func__);
diff --git a/drivers/misc/tsl2550.c b/drivers/misc/tsl2550.c
index 09db397df287..6d71865c8042 100644
--- a/drivers/misc/tsl2550.c
+++ b/drivers/misc/tsl2550.c
@@ -148,16 +148,14 @@ static int tsl2550_calculate_lux(u8 ch0, u8 ch1)
u16 c0 = count_lut[ch0];
u16 c1 = count_lut[ch1];
- /*
- * Calculate ratio.
- * Note: the "128" is a scaling factor
- */
- u8 r = 128;
-
/* Avoid division by 0 and count 1 cannot be greater than count 0 */
if (c1 <= c0)
if (c0) {
- r = c1 * 128 / c0;
+ /*
+ * Calculate ratio.
+ * Note: the "128" is a scaling factor
+ */
+ u8 r = c1 * 128 / c0;
/* Calculate LUX */
lux = ((c0 - c1) * ratio_lut[r]) / 256;
diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c
index 11835969e982..71bbaa56bdb5 100644
--- a/drivers/misc/xilinx_sdfec.c
+++ b/drivers/misc/xilinx_sdfec.c
@@ -733,7 +733,7 @@ static int xsdfec_set_order(struct xsdfec_dev *xsdfec, void __user *arg)
enum xsdfec_order order;
int err;
- err = get_user(order, (enum xsdfec_order *)arg);
+ err = get_user(order, (enum xsdfec_order __user *)arg);
if (err)
return -EFAULT;
@@ -1025,25 +1025,25 @@ static long xsdfec_dev_compat_ioctl(struct file *file, unsigned int cmd,
}
#endif
-static unsigned int xsdfec_poll(struct file *file, poll_table *wait)
+static __poll_t xsdfec_poll(struct file *file, poll_table *wait)
{
- unsigned int mask = 0;
+ __poll_t mask = 0;
struct xsdfec_dev *xsdfec;
xsdfec = container_of(file->private_data, struct xsdfec_dev, miscdev);
if (!xsdfec)
- return POLLNVAL | POLLHUP;
+ return EPOLLNVAL | EPOLLHUP;
poll_wait(file, &xsdfec->waitq, wait);
/* XSDFEC ISR detected an error */
spin_lock_irqsave(&xsdfec->error_data_lock, xsdfec->flags);
if (xsdfec->state_updated)
- mask |= POLLIN | POLLPRI;
+ mask |= EPOLLIN | EPOLLPRI;
if (xsdfec->stats_updated)
- mask |= POLLIN | POLLRDNORM;
+ mask |= EPOLLIN | EPOLLRDNORM;
spin_unlock_irqrestore(&xsdfec->error_data_lock, xsdfec->flags);
return mask;
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 73567e922491..35efab1ba8d9 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -109,6 +109,14 @@ config QCOM_QFPROM
This driver can also be built as a module. If so, the module
will be called nvmem_qfprom.
+config NVMEM_SPMI_SDAM
+ tristate "SPMI SDAM Support"
+ depends on SPMI
+ help
+ This driver supports the Shared Direct Access Memory Module on
+ Qualcomm Technologies, Inc. PMICs. It provides the clients
+ an interface to read/write to the SDAM module's shared memory.
+
config ROCKCHIP_EFUSE
tristate "Rockchip eFuse Support"
depends on ARCH_ROCKCHIP || COMPILE_TEST
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 9e667823edb3..6b466cd1427b 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -28,6 +28,8 @@ obj-$(CONFIG_MTK_EFUSE) += nvmem_mtk-efuse.o
nvmem_mtk-efuse-y := mtk-efuse.o
obj-$(CONFIG_QCOM_QFPROM) += nvmem_qfprom.o
nvmem_qfprom-y := qfprom.o
+obj-$(CONFIG_NVMEM_SPMI_SDAM) += nvmem_qcom-spmi-sdam.o
+nvmem_qcom-spmi-sdam-y += qcom-spmi-sdam.o
obj-$(CONFIG_ROCKCHIP_EFUSE) += nvmem_rockchip_efuse.o
nvmem_rockchip_efuse-y := rockchip-efuse.o
obj-$(CONFIG_ROCKCHIP_OTP) += nvmem-rockchip-otp.o
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 9f1ee9c766ec..1e4a798dce6e 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -83,7 +83,7 @@ static void nvmem_cell_drop(struct nvmem_cell *cell)
list_del(&cell->node);
mutex_unlock(&nvmem_mutex);
of_node_put(cell->np);
- kfree(cell->name);
+ kfree_const(cell->name);
kfree(cell);
}
@@ -110,7 +110,9 @@ static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem,
cell->nvmem = nvmem;
cell->offset = info->offset;
cell->bytes = info->bytes;
- cell->name = info->name;
+ cell->name = kstrdup_const(info->name, GFP_KERNEL);
+ if (!cell->name)
+ return -ENOMEM;
cell->bit_offset = info->bit_offset;
cell->nbits = info->nbits;
@@ -300,7 +302,7 @@ static int nvmem_add_cells_from_of(struct nvmem_device *nvmem)
dev_err(dev, "cell %s unaligned to nvmem stride %d\n",
cell->name, nvmem->stride);
/* Cells already added will be freed later. */
- kfree(cell->name);
+ kfree_const(cell->name);
kfree(cell);
return -EINVAL;
}
diff --git a/drivers/nvmem/imx-ocotp-scu.c b/drivers/nvmem/imx-ocotp-scu.c
index 03f1ab23ad51..399e1eb8b4c1 100644
--- a/drivers/nvmem/imx-ocotp-scu.c
+++ b/drivers/nvmem/imx-ocotp-scu.c
@@ -15,8 +15,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
-#define IMX_SIP_OTP 0xC200000A
-#define IMX_SIP_OTP_WRITE 0x2
+#define IMX_SIP_OTP_WRITE 0xc200000B
enum ocotp_devtype {
IMX8QXP,
@@ -139,8 +138,8 @@ static int imx_scu_ocotp_read(void *context, unsigned int offset,
void *p;
int i, ret;
- index = offset >> 2;
- num_bytes = round_up((offset % 4) + bytes, 4);
+ index = offset;
+ num_bytes = round_up(bytes, 4);
count = num_bytes >> 2;
if (count > (priv->data->nregs - index))
@@ -169,7 +168,7 @@ static int imx_scu_ocotp_read(void *context, unsigned int offset,
buf++;
}
- memcpy(val, (u8 *)p + offset % 4, bytes);
+ memcpy(val, (u8 *)p, bytes);
mutex_unlock(&scu_ocotp_mutex);
@@ -189,10 +188,10 @@ static int imx_scu_ocotp_write(void *context, unsigned int offset,
int ret;
/* allow only writing one complete OTP word at a time */
- if ((bytes != 4) || (offset % 4))
+ if (bytes != 4)
return -EINVAL;
- index = offset >> 2;
+ index = offset;
if (in_hole(context, index))
return -EINVAL;
@@ -212,8 +211,7 @@ static int imx_scu_ocotp_write(void *context, unsigned int offset,
mutex_lock(&scu_ocotp_mutex);
- arm_smccc_smc(IMX_SIP_OTP, IMX_SIP_OTP_WRITE, index, *buf,
- 0, 0, 0, 0, &res);
+ arm_smccc_smc(IMX_SIP_OTP_WRITE, index, *buf, 0, 0, 0, 0, 0, &res);
mutex_unlock(&scu_ocotp_mutex);
diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
index fc40555ca4cd..4ba9cc8f76df 100644
--- a/drivers/nvmem/imx-ocotp.c
+++ b/drivers/nvmem/imx-ocotp.c
@@ -44,6 +44,14 @@
#define IMX_OCOTP_BM_CTRL_ERROR 0x00000200
#define IMX_OCOTP_BM_CTRL_REL_SHADOWS 0x00000400
+#define IMX_OCOTP_BM_CTRL_DEFAULT \
+ { \
+ .bm_addr = IMX_OCOTP_BM_CTRL_ADDR, \
+ .bm_busy = IMX_OCOTP_BM_CTRL_BUSY, \
+ .bm_error = IMX_OCOTP_BM_CTRL_ERROR, \
+ .bm_rel_shadows = IMX_OCOTP_BM_CTRL_REL_SHADOWS,\
+ }
+
#define TIMING_STROBE_PROG_US 10 /* Min time to blow a fuse */
#define TIMING_STROBE_READ_NS 37 /* Min time before read */
#define TIMING_RELAX_NS 17
@@ -62,18 +70,31 @@ struct ocotp_priv {
struct nvmem_config *config;
};
+struct ocotp_ctrl_reg {
+ u32 bm_addr;
+ u32 bm_busy;
+ u32 bm_error;
+ u32 bm_rel_shadows;
+};
+
struct ocotp_params {
unsigned int nregs;
unsigned int bank_address_words;
void (*set_timing)(struct ocotp_priv *priv);
+ struct ocotp_ctrl_reg ctrl;
};
-static int imx_ocotp_wait_for_busy(void __iomem *base, u32 flags)
+static int imx_ocotp_wait_for_busy(struct ocotp_priv *priv, u32 flags)
{
int count;
u32 c, mask;
+ u32 bm_ctrl_busy, bm_ctrl_error;
+ void __iomem *base = priv->base;
- mask = IMX_OCOTP_BM_CTRL_BUSY | IMX_OCOTP_BM_CTRL_ERROR | flags;
+ bm_ctrl_busy = priv->params->ctrl.bm_busy;
+ bm_ctrl_error = priv->params->ctrl.bm_error;
+
+ mask = bm_ctrl_busy | bm_ctrl_error | flags;
for (count = 10000; count >= 0; count--) {
c = readl(base + IMX_OCOTP_ADDR_CTRL);
@@ -97,7 +118,7 @@ static int imx_ocotp_wait_for_busy(void __iomem *base, u32 flags)
* - A read is performed to from a fuse word which has been read
* locked.
*/
- if (c & IMX_OCOTP_BM_CTRL_ERROR)
+ if (c & bm_ctrl_error)
return -EPERM;
return -ETIMEDOUT;
}
@@ -105,15 +126,18 @@ static int imx_ocotp_wait_for_busy(void __iomem *base, u32 flags)
return 0;
}
-static void imx_ocotp_clr_err_if_set(void __iomem *base)
+static void imx_ocotp_clr_err_if_set(struct ocotp_priv *priv)
{
- u32 c;
+ u32 c, bm_ctrl_error;
+ void __iomem *base = priv->base;
+
+ bm_ctrl_error = priv->params->ctrl.bm_error;
c = readl(base + IMX_OCOTP_ADDR_CTRL);
- if (!(c & IMX_OCOTP_BM_CTRL_ERROR))
+ if (!(c & bm_ctrl_error))
return;
- writel(IMX_OCOTP_BM_CTRL_ERROR, base + IMX_OCOTP_ADDR_CTRL_CLR);
+ writel(bm_ctrl_error, base + IMX_OCOTP_ADDR_CTRL_CLR);
}
static int imx_ocotp_read(void *context, unsigned int offset,
@@ -140,7 +164,7 @@ static int imx_ocotp_read(void *context, unsigned int offset,
return ret;
}
- ret = imx_ocotp_wait_for_busy(priv->base, 0);
+ ret = imx_ocotp_wait_for_busy(priv, 0);
if (ret < 0) {
dev_err(priv->dev, "timeout during read setup\n");
goto read_end;
@@ -157,7 +181,7 @@ static int imx_ocotp_read(void *context, unsigned int offset,
* issued
*/
if (*(buf - 1) == IMX_OCOTP_READ_LOCKED_VAL)
- imx_ocotp_clr_err_if_set(priv->base);
+ imx_ocotp_clr_err_if_set(priv);
}
ret = 0;
@@ -274,7 +298,7 @@ static int imx_ocotp_write(void *context, unsigned int offset, void *val,
* write or reload must be completed before a write access can be
* requested.
*/
- ret = imx_ocotp_wait_for_busy(priv->base, 0);
+ ret = imx_ocotp_wait_for_busy(priv, 0);
if (ret < 0) {
dev_err(priv->dev, "timeout during timing setup\n");
goto write_end;
@@ -306,8 +330,8 @@ static int imx_ocotp_write(void *context, unsigned int offset, void *val,
}
ctrl = readl(priv->base + IMX_OCOTP_ADDR_CTRL);
- ctrl &= ~IMX_OCOTP_BM_CTRL_ADDR;
- ctrl |= waddr & IMX_OCOTP_BM_CTRL_ADDR;
+ ctrl &= ~priv->params->ctrl.bm_addr;
+ ctrl |= waddr & priv->params->ctrl.bm_addr;
ctrl |= IMX_OCOTP_WR_UNLOCK;
writel(ctrl, priv->base + IMX_OCOTP_ADDR_CTRL);
@@ -374,11 +398,11 @@ static int imx_ocotp_write(void *context, unsigned int offset, void *val,
* be set. It must be cleared by software before any new write access
* can be issued.
*/
- ret = imx_ocotp_wait_for_busy(priv->base, 0);
+ ret = imx_ocotp_wait_for_busy(priv, 0);
if (ret < 0) {
if (ret == -EPERM) {
dev_err(priv->dev, "failed write to locked region");
- imx_ocotp_clr_err_if_set(priv->base);
+ imx_ocotp_clr_err_if_set(priv);
} else {
dev_err(priv->dev, "timeout during data write\n");
}
@@ -394,10 +418,10 @@ static int imx_ocotp_write(void *context, unsigned int offset, void *val,
udelay(2);
/* reload all shadow registers */
- writel(IMX_OCOTP_BM_CTRL_REL_SHADOWS,
+ writel(priv->params->ctrl.bm_rel_shadows,
priv->base + IMX_OCOTP_ADDR_CTRL_SET);
- ret = imx_ocotp_wait_for_busy(priv->base,
- IMX_OCOTP_BM_CTRL_REL_SHADOWS);
+ ret = imx_ocotp_wait_for_busy(priv,
+ priv->params->ctrl.bm_rel_shadows);
if (ret < 0) {
dev_err(priv->dev, "timeout during shadow register reload\n");
goto write_end;
@@ -424,65 +448,76 @@ static const struct ocotp_params imx6q_params = {
.nregs = 128,
.bank_address_words = 0,
.set_timing = imx_ocotp_set_imx6_timing,
+ .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
};
static const struct ocotp_params imx6sl_params = {
.nregs = 64,
.bank_address_words = 0,
.set_timing = imx_ocotp_set_imx6_timing,
+ .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
};
static const struct ocotp_params imx6sll_params = {
.nregs = 128,
.bank_address_words = 0,
.set_timing = imx_ocotp_set_imx6_timing,
+ .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
};
static const struct ocotp_params imx6sx_params = {
.nregs = 128,
.bank_address_words = 0,
.set_timing = imx_ocotp_set_imx6_timing,
+ .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
};
static const struct ocotp_params imx6ul_params = {
.nregs = 128,
.bank_address_words = 0,
.set_timing = imx_ocotp_set_imx6_timing,
+ .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
};
static const struct ocotp_params imx6ull_params = {
.nregs = 64,
.bank_address_words = 0,
.set_timing = imx_ocotp_set_imx6_timing,
+ .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
};
static const struct ocotp_params imx7d_params = {
.nregs = 64,
.bank_address_words = 4,
.set_timing = imx_ocotp_set_imx7_timing,
+ .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
};
static const struct ocotp_params imx7ulp_params = {
.nregs = 256,
.bank_address_words = 0,
+ .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
};
static const struct ocotp_params imx8mq_params = {
.nregs = 256,
.bank_address_words = 0,
.set_timing = imx_ocotp_set_imx6_timing,
+ .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
};
static const struct ocotp_params imx8mm_params = {
.nregs = 256,
.bank_address_words = 0,
.set_timing = imx_ocotp_set_imx6_timing,
+ .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
};
static const struct ocotp_params imx8mn_params = {
.nregs = 256,
.bank_address_words = 0,
.set_timing = imx_ocotp_set_imx6_timing,
+ .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
};
static const struct of_device_id imx_ocotp_dt_ids[] = {
@@ -521,17 +556,17 @@ static int imx_ocotp_probe(struct platform_device *pdev)
if (IS_ERR(priv->clk))
return PTR_ERR(priv->clk);
- clk_prepare_enable(priv->clk);
- imx_ocotp_clr_err_if_set(priv->base);
- clk_disable_unprepare(priv->clk);
-
priv->params = of_device_get_match_data(&pdev->dev);
imx_ocotp_nvmem_config.size = 4 * priv->params->nregs;
imx_ocotp_nvmem_config.dev = dev;
imx_ocotp_nvmem_config.priv = priv;
priv->config = &imx_ocotp_nvmem_config;
- nvmem = devm_nvmem_register(dev, &imx_ocotp_nvmem_config);
+ clk_prepare_enable(priv->clk);
+ imx_ocotp_clr_err_if_set(priv);
+ clk_disable_unprepare(priv->clk);
+
+ nvmem = devm_nvmem_register(dev, &imx_ocotp_nvmem_config);
return PTR_ERR_OR_ZERO(nvmem);
}
diff --git a/drivers/nvmem/qcom-spmi-sdam.c b/drivers/nvmem/qcom-spmi-sdam.c
new file mode 100644
index 000000000000..8682cda448d6
--- /dev/null
+++ b/drivers/nvmem/qcom-spmi-sdam.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/nvmem-provider.h>
+#include <linux/regmap.h>
+
+#define SDAM_MEM_START 0x40
+#define REGISTER_MAP_ID 0x40
+#define REGISTER_MAP_VERSION 0x41
+#define SDAM_SIZE 0x44
+#define SDAM_PBS_TRIG_SET 0xE5
+#define SDAM_PBS_TRIG_CLR 0xE6
+
+struct sdam_chip {
+ struct platform_device *pdev;
+ struct regmap *regmap;
+ struct nvmem_config sdam_config;
+ unsigned int base;
+ unsigned int size;
+};
+
+/* read only register offsets */
+static const u8 sdam_ro_map[] = {
+ REGISTER_MAP_ID,
+ REGISTER_MAP_VERSION,
+ SDAM_SIZE
+};
+
+static bool sdam_is_valid(struct sdam_chip *sdam, unsigned int offset,
+ size_t len)
+{
+ unsigned int sdam_mem_end = SDAM_MEM_START + sdam->size - 1;
+
+ if (!len)
+ return false;
+
+ if (offset >= SDAM_MEM_START && offset <= sdam_mem_end
+ && (offset + len - 1) <= sdam_mem_end)
+ return true;
+ else if ((offset == SDAM_PBS_TRIG_SET || offset == SDAM_PBS_TRIG_CLR)
+ && (len == 1))
+ return true;
+
+ return false;
+}
+
+static bool sdam_is_ro(unsigned int offset, size_t len)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sdam_ro_map); i++)
+ if (offset <= sdam_ro_map[i] && (offset + len) > sdam_ro_map[i])
+ return true;
+
+ return false;
+}
+
+static int sdam_read(void *priv, unsigned int offset, void *val,
+ size_t bytes)
+{
+ struct sdam_chip *sdam = priv;
+ struct device *dev = &sdam->pdev->dev;
+ int rc;
+
+ if (!sdam_is_valid(sdam, offset, bytes)) {
+ dev_err(dev, "Invalid SDAM offset %#x len=%zd\n",
+ offset, bytes);
+ return -EINVAL;
+ }
+
+ rc = regmap_bulk_read(sdam->regmap, sdam->base + offset, val, bytes);
+ if (rc < 0)
+ dev_err(dev, "Failed to read SDAM offset %#x len=%zd, rc=%d\n",
+ offset, bytes, rc);
+
+ return rc;
+}
+
+static int sdam_write(void *priv, unsigned int offset, void *val,
+ size_t bytes)
+{
+ struct sdam_chip *sdam = priv;
+ struct device *dev = &sdam->pdev->dev;
+ int rc;
+
+ if (!sdam_is_valid(sdam, offset, bytes)) {
+ dev_err(dev, "Invalid SDAM offset %#x len=%zd\n",
+ offset, bytes);
+ return -EINVAL;
+ }
+
+ if (sdam_is_ro(offset, bytes)) {
+ dev_err(dev, "Invalid write offset %#x len=%zd\n",
+ offset, bytes);
+ return -EINVAL;
+ }
+
+ rc = regmap_bulk_write(sdam->regmap, sdam->base + offset, val, bytes);
+ if (rc < 0)
+ dev_err(dev, "Failed to write SDAM offset %#x len=%zd, rc=%d\n",
+ offset, bytes, rc);
+
+ return rc;
+}
+
+static int sdam_probe(struct platform_device *pdev)
+{
+ struct sdam_chip *sdam;
+ struct nvmem_device *nvmem;
+ unsigned int val;
+ int rc;
+
+ sdam = devm_kzalloc(&pdev->dev, sizeof(*sdam), GFP_KERNEL);
+ if (!sdam)
+ return -ENOMEM;
+
+ sdam->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!sdam->regmap) {
+ dev_err(&pdev->dev, "Failed to get regmap handle\n");
+ return -ENXIO;
+ }
+
+ rc = of_property_read_u32(pdev->dev.of_node, "reg", &sdam->base);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "Failed to get SDAM base, rc=%d\n", rc);
+ return -EINVAL;
+ }
+
+ rc = regmap_read(sdam->regmap, sdam->base + SDAM_SIZE, &val);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "Failed to read SDAM_SIZE rc=%d\n", rc);
+ return -EINVAL;
+ }
+ sdam->size = val * 32;
+
+ sdam->sdam_config.dev = &pdev->dev;
+ sdam->sdam_config.name = "spmi_sdam";
+ sdam->sdam_config.id = pdev->id;
+ sdam->sdam_config.owner = THIS_MODULE,
+ sdam->sdam_config.stride = 1;
+ sdam->sdam_config.word_size = 1;
+ sdam->sdam_config.reg_read = sdam_read;
+ sdam->sdam_config.reg_write = sdam_write;
+ sdam->sdam_config.priv = sdam;
+
+ nvmem = devm_nvmem_register(&pdev->dev, &sdam->sdam_config);
+ if (IS_ERR(nvmem)) {
+ dev_err(&pdev->dev,
+ "Failed to register SDAM nvmem device rc=%ld\n",
+ PTR_ERR(nvmem));
+ return -ENXIO;
+ }
+ dev_dbg(&pdev->dev,
+ "SDAM base=%#x size=%u registered successfully\n",
+ sdam->base, sdam->size);
+
+ return 0;
+}
+
+static const struct of_device_id sdam_match_table[] = {
+ { .compatible = "qcom,spmi-sdam" },
+ {},
+};
+
+static struct platform_driver sdam_driver = {
+ .driver = {
+ .name = "qcom,spmi-sdam",
+ .of_match_table = sdam_match_table,
+ },
+ .probe = sdam_probe,
+};
+
+static int __init sdam_init(void)
+{
+ return platform_driver_register(&sdam_driver);
+}
+subsys_initcall(sdam_init);
+
+static void __exit sdam_exit(void)
+{
+ return platform_driver_unregister(&sdam_driver);
+}
+module_exit(sdam_exit);
+
+MODULE_DESCRIPTION("QCOM SPMI SDAM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/siox/siox.h b/drivers/siox/siox.h
index c674bf6fb119..f08b43b713c5 100644
--- a/drivers/siox/siox.h
+++ b/drivers/siox/siox.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2015-2017 Pengutronix, Uwe Kleine-König <kernel@pengutronix.de>
*/
diff --git a/drivers/slimbus/qcom-ctrl.c b/drivers/slimbus/qcom-ctrl.c
index a444badd8df5..4aad2566f52d 100644
--- a/drivers/slimbus/qcom-ctrl.c
+++ b/drivers/slimbus/qcom-ctrl.c
@@ -641,6 +641,8 @@ static int qcom_slim_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
slim_unregister_controller(&ctrl->ctrl);
+ clk_disable_unprepare(ctrl->rclk);
+ clk_disable_unprepare(ctrl->hclk);
destroy_workqueue(ctrl->rxwq);
return 0;
}
diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c
index 29fbab55c3b3..e3f5ebc0c05e 100644
--- a/drivers/slimbus/qcom-ngd-ctrl.c
+++ b/drivers/slimbus/qcom-ngd-ctrl.c
@@ -666,10 +666,12 @@ static int qcom_slim_ngd_init_rx_msgq(struct qcom_slim_ngd_ctrl *ctrl)
struct device *dev = ctrl->dev;
int ret, size;
- ctrl->dma_rx_channel = dma_request_slave_channel(dev, "rx");
- if (!ctrl->dma_rx_channel) {
- dev_err(dev, "Failed to request dma channels");
- return -EINVAL;
+ ctrl->dma_rx_channel = dma_request_chan(dev, "rx");
+ if (IS_ERR(ctrl->dma_rx_channel)) {
+ dev_err(dev, "Failed to request RX dma channel");
+ ret = PTR_ERR(ctrl->dma_rx_channel);
+ ctrl->dma_rx_channel = NULL;
+ return ret;
}
size = QCOM_SLIM_NGD_DESC_NUM * SLIM_MSGQ_BUF_LEN;
@@ -703,10 +705,12 @@ static int qcom_slim_ngd_init_tx_msgq(struct qcom_slim_ngd_ctrl *ctrl)
int ret = 0;
int size;
- ctrl->dma_tx_channel = dma_request_slave_channel(dev, "tx");
- if (!ctrl->dma_tx_channel) {
- dev_err(dev, "Failed to request dma channels");
- return -EINVAL;
+ ctrl->dma_tx_channel = dma_request_chan(dev, "tx");
+ if (IS_ERR(ctrl->dma_tx_channel)) {
+ dev_err(dev, "Failed to request TX dma channel");
+ ret = PTR_ERR(ctrl->dma_tx_channel);
+ ctrl->dma_tx_channel = NULL;
+ return ret;
}
size = ((QCOM_SLIM_NGD_DESC_NUM + 1) * SLIM_MSGQ_BUF_LEN);
diff --git a/drivers/slimbus/slimbus.h b/drivers/slimbus/slimbus.h
index b2f013bfe42e..c73035915f1d 100644
--- a/drivers/slimbus/slimbus.h
+++ b/drivers/slimbus/slimbus.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2011-2017, The Linux Foundation
*/
diff --git a/drivers/soundwire/Kconfig b/drivers/soundwire/Kconfig
index c725d0a8b288..fa2b4ab92ed9 100644
--- a/drivers/soundwire/Kconfig
+++ b/drivers/soundwire/Kconfig
@@ -31,4 +31,13 @@ config SOUNDWIRE_INTEL
enable this config option to get the SoundWire support for that
device.
+config SOUNDWIRE_QCOM
+ tristate "Qualcomm SoundWire Master driver"
+ depends on SLIMBUS
+ depends on SND_SOC
+ help
+ SoundWire Qualcomm Master driver.
+ If you have an Qualcomm platform which has a SoundWire Master then
+ enable this config option to get the SoundWire support for that
+ device
endif
diff --git a/drivers/soundwire/Makefile b/drivers/soundwire/Makefile
index 563894e5ecaf..e2cdff990e9f 100644
--- a/drivers/soundwire/Makefile
+++ b/drivers/soundwire/Makefile
@@ -21,3 +21,7 @@ obj-$(CONFIG_SOUNDWIRE_INTEL) += soundwire-intel.o
soundwire-intel-init-objs := intel_init.o
obj-$(CONFIG_SOUNDWIRE_INTEL) += soundwire-intel-init.o
+
+#Qualcomm driver
+soundwire-qcom-objs := qcom.o
+obj-$(CONFIG_SOUNDWIRE_QCOM) += soundwire-qcom.o
diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index be5d437058ed..6106577fb3ed 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -456,26 +456,35 @@ err:
static int sdw_assign_device_num(struct sdw_slave *slave)
{
int ret, dev_num;
+ bool new_device = false;
/* check first if device number is assigned, if so reuse that */
if (!slave->dev_num) {
- mutex_lock(&slave->bus->bus_lock);
- dev_num = sdw_get_device_num(slave);
- mutex_unlock(&slave->bus->bus_lock);
- if (dev_num < 0) {
- dev_err(slave->bus->dev, "Get dev_num failed: %d\n",
- dev_num);
- return dev_num;
+ if (!slave->dev_num_sticky) {
+ mutex_lock(&slave->bus->bus_lock);
+ dev_num = sdw_get_device_num(slave);
+ mutex_unlock(&slave->bus->bus_lock);
+ if (dev_num < 0) {
+ dev_err(slave->bus->dev, "Get dev_num failed: %d\n",
+ dev_num);
+ return dev_num;
+ }
+ slave->dev_num = dev_num;
+ slave->dev_num_sticky = dev_num;
+ new_device = true;
+ } else {
+ slave->dev_num = slave->dev_num_sticky;
}
- } else {
+ }
+
+ if (!new_device)
dev_info(slave->bus->dev,
- "Slave already registered dev_num:%d\n",
+ "Slave already registered, reusing dev_num:%d\n",
slave->dev_num);
- /* Clear the slave->dev_num to transfer message on device 0 */
- dev_num = slave->dev_num;
- slave->dev_num = 0;
- }
+ /* Clear the slave->dev_num to transfer message on device 0 */
+ dev_num = slave->dev_num;
+ slave->dev_num = 0;
ret = sdw_write(slave, SDW_SCP_DEVNUMBER, dev_num);
if (ret < 0) {
@@ -485,7 +494,7 @@ static int sdw_assign_device_num(struct sdw_slave *slave)
}
/* After xfer of msg, restore dev_num */
- slave->dev_num = dev_num;
+ slave->dev_num = slave->dev_num_sticky;
return 0;
}
@@ -979,6 +988,24 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
struct sdw_slave *slave;
int i, ret = 0;
+ /* first check if any Slaves fell off the bus */
+ for (i = 1; i <= SDW_MAX_DEVICES; i++) {
+ mutex_lock(&bus->bus_lock);
+ if (test_bit(i, bus->assigned) == false) {
+ mutex_unlock(&bus->bus_lock);
+ continue;
+ }
+ mutex_unlock(&bus->bus_lock);
+
+ slave = sdw_get_slave(bus, i);
+ if (!slave)
+ continue;
+
+ if (status[i] == SDW_SLAVE_UNATTACHED &&
+ slave->status != SDW_SLAVE_UNATTACHED)
+ sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED);
+ }
+
if (status[0] == SDW_SLAVE_ATTACHED) {
dev_dbg(bus->dev, "Slave attached, programming device number\n");
ret = sdw_program_device_num(bus);
diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index fed21e2b2277..9bec270d0fa4 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -74,6 +74,7 @@ MODULE_PARM_DESC(cdns_mcp_int_mask, "Cadence MCP IntMask");
#define CDNS_MCP_INTMASK 0x48
#define CDNS_MCP_INT_IRQ BIT(31)
+#define CDNS_MCP_INT_RESERVED1 GENMASK(30, 17)
#define CDNS_MCP_INT_WAKEUP BIT(16)
#define CDNS_MCP_INT_SLAVE_RSVD BIT(15)
#define CDNS_MCP_INT_SLAVE_ALERT BIT(14)
@@ -85,10 +86,12 @@ MODULE_PARM_DESC(cdns_mcp_int_mask, "Cadence MCP IntMask");
#define CDNS_MCP_INT_DATA_CLASH BIT(9)
#define CDNS_MCP_INT_PARITY BIT(8)
#define CDNS_MCP_INT_CMD_ERR BIT(7)
+#define CDNS_MCP_INT_RESERVED2 GENMASK(6, 4)
#define CDNS_MCP_INT_RX_NE BIT(3)
#define CDNS_MCP_INT_RX_WL BIT(2)
#define CDNS_MCP_INT_TXE BIT(1)
#define CDNS_MCP_INT_TXF BIT(0)
+#define CDNS_MCP_INT_RESERVED (CDNS_MCP_INT_RESERVED1 | CDNS_MCP_INT_RESERVED2)
#define CDNS_MCP_INTSET 0x4C
@@ -444,7 +447,8 @@ _cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd,
time = wait_for_completion_timeout(&cdns->tx_complete,
msecs_to_jiffies(CDNS_TX_TIMEOUT));
if (!time) {
- dev_err(cdns->dev, "IO transfer timed out\n");
+ dev_err(cdns->dev, "IO transfer timed out, cmd %d device %d addr %x len %d\n",
+ cmd, msg->dev_num, msg->addr, msg->len);
msg->len = 0;
return SDW_CMD_TIMEOUT;
}
@@ -672,13 +676,36 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns,
/* first check if Slave reported multiple status */
if (set_status > 1) {
+ u32 val;
+
+ dev_warn_ratelimited(cdns->dev,
+ "Slave %d reported multiple Status: %d\n",
+ i, mask);
+
+ /* check latest status extracted from PING commands */
+ val = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);
+ val >>= (i * 2);
+
+ switch (val & 0x3) {
+ case 0:
+ status[i] = SDW_SLAVE_UNATTACHED;
+ break;
+ case 1:
+ status[i] = SDW_SLAVE_ATTACHED;
+ break;
+ case 2:
+ status[i] = SDW_SLAVE_ALERT;
+ break;
+ case 3:
+ default:
+ status[i] = SDW_SLAVE_RESERVED;
+ break;
+ }
+
dev_warn_ratelimited(cdns->dev,
- "Slave reported multiple Status: %d\n",
- mask);
- /*
- * TODO: we need to reread the status here by
- * issuing a PING cmd
- */
+ "Slave %d status updated to %d\n",
+ i, status[i]);
+
}
}
@@ -705,6 +732,10 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id)
int_status = cdns_readl(cdns, CDNS_MCP_INTSTAT);
+ /* check for reserved values read as zero */
+ if (int_status & CDNS_MCP_INT_RESERVED)
+ return IRQ_NONE;
+
if (!(int_status & CDNS_MCP_INT_IRQ))
return IRQ_NONE;
@@ -812,8 +843,9 @@ int sdw_cdns_exit_reset(struct sdw_cdns *cdns)
EXPORT_SYMBOL(sdw_cdns_exit_reset);
/**
- * sdw_cdns_enable_interrupt() - Enable SDW interrupts and update config
+ * sdw_cdns_enable_interrupt() - Enable SDW interrupts
* @cdns: Cadence instance
+ * @state: True if we are trying to enable interrupt.
*/
int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns, bool state)
{
@@ -849,12 +881,21 @@ int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns, bool state)
mask = interrupt_mask;
update_masks:
+ /* clear slave interrupt status before enabling interrupt */
+ if (state) {
+ u32 slave_state;
+
+ slave_state = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT0);
+ cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT0, slave_state);
+ slave_state = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT1);
+ cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT1, slave_state);
+ }
+
cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK0, slave_intmask0);
cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1, slave_intmask1);
cdns_writel(cdns, CDNS_MCP_INTMASK, mask);
- /* commit changes */
- return cdns_update_config(cdns);
+ return 0;
}
EXPORT_SYMBOL(sdw_cdns_enable_interrupt);
@@ -948,8 +989,6 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
ret = cdns_allocate_pdi(cdns, &stream->out,
stream->num_out, offset);
- offset += stream->num_out;
-
if (ret)
return ret;
@@ -1224,8 +1263,10 @@ EXPORT_SYMBOL(cdns_set_sdw_stream);
* cdns_find_pdi() - Find a free PDI
*
* @cdns: Cadence instance
+ * @offset: Starting offset
* @num: Number of PDIs
* @pdi: PDI instances
+ * @dai_id: DAI id
*
* Find a PDI for a given PDI array. The PDI num and dai_id are
* expected to match, return NULL otherwise.
@@ -1277,6 +1318,7 @@ EXPORT_SYMBOL(sdw_cdns_config_stream);
* @stream: Stream to be allocated
* @ch: Channel count
* @dir: Data direction
+ * @dai_id: DAI id
*/
struct sdw_cdns_pdi *sdw_cdns_alloc_pdi(struct sdw_cdns *cdns,
struct sdw_cdns_streams *stream,
diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index 0371d3d5501a..06ef3a3ac080 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -880,6 +880,9 @@ static int sdw_master_read_intel_prop(struct sdw_bus *bus)
"intel-sdw-ip-clock",
&prop->mclk_freq);
+ /* the values reported by BIOS are the 2x clock, not the bus clock */
+ prop->mclk_freq /= 2;
+
fwnode_property_read_u32(link,
"intel-quirk-mask",
&quirk_mask);
diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
new file mode 100644
index 000000000000..1c6c6a2e0def
--- /dev/null
+++ b/drivers/soundwire/qcom.c
@@ -0,0 +1,861 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019, Linaro Limited
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/slimbus.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "bus.h"
+
+#define SWRM_COMP_HW_VERSION 0x00
+#define SWRM_COMP_CFG_ADDR 0x04
+#define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK BIT(1)
+#define SWRM_COMP_CFG_ENABLE_MSK BIT(0)
+#define SWRM_COMP_PARAMS 0x100
+#define SWRM_COMP_PARAMS_DOUT_PORTS_MASK GENMASK(4, 0)
+#define SWRM_COMP_PARAMS_DIN_PORTS_MASK GENMASK(9, 5)
+#define SWRM_INTERRUPT_STATUS 0x200
+#define SWRM_INTERRUPT_STATUS_RMSK GENMASK(16, 0)
+#define SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED BIT(1)
+#define SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS BIT(2)
+#define SWRM_INTERRUPT_STATUS_CMD_ERROR BIT(7)
+#define SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED BIT(10)
+#define SWRM_INTERRUPT_MASK_ADDR 0x204
+#define SWRM_INTERRUPT_CLEAR 0x208
+#define SWRM_CMD_FIFO_WR_CMD 0x300
+#define SWRM_CMD_FIFO_RD_CMD 0x304
+#define SWRM_CMD_FIFO_CMD 0x308
+#define SWRM_CMD_FIFO_STATUS 0x30C
+#define SWRM_CMD_FIFO_CFG_ADDR 0x314
+#define SWRM_RD_WR_CMD_RETRIES 0x7
+#define SWRM_CMD_FIFO_RD_FIFO_ADDR 0x318
+#define SWRM_ENUMERATOR_CFG_ADDR 0x500
+#define SWRM_MCP_FRAME_CTRL_BANK_ADDR(m) (0x101C + 0x40 * (m))
+#define SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT 3
+#define SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK GENMASK(2, 0)
+#define SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK GENMASK(7, 3)
+#define SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT 0
+#define SWRM_MCP_CFG_ADDR 0x1048
+#define SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK GENMASK(21, 17)
+#define SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_SHFT 0x11
+#define SWRM_DEF_CMD_NO_PINGS 0x1f
+#define SWRM_MCP_STATUS 0x104C
+#define SWRM_MCP_STATUS_BANK_NUM_MASK BIT(0)
+#define SWRM_MCP_SLV_STATUS 0x1090
+#define SWRM_MCP_SLV_STATUS_MASK GENMASK(1, 0)
+#define SWRM_DP_PORT_CTRL_BANK(n, m) (0x1124 + 0x100 * (n - 1) + 0x40 * m)
+#define SWRM_DP_PORT_CTRL_EN_CHAN_SHFT 0x18
+#define SWRM_DP_PORT_CTRL_OFFSET2_SHFT 0x10
+#define SWRM_DP_PORT_CTRL_OFFSET1_SHFT 0x08
+#define SWRM_AHB_BRIDGE_WR_DATA_0 0xc85
+#define SWRM_AHB_BRIDGE_WR_ADDR_0 0xc89
+#define SWRM_AHB_BRIDGE_RD_ADDR_0 0xc8d
+#define SWRM_AHB_BRIDGE_RD_DATA_0 0xc91
+
+#define SWRM_REG_VAL_PACK(data, dev, id, reg) \
+ ((reg) | ((id) << 16) | ((dev) << 20) | ((data) << 24))
+
+#define SWRM_MAX_ROW_VAL 0 /* Rows = 48 */
+#define SWRM_DEFAULT_ROWS 48
+#define SWRM_MIN_COL_VAL 0 /* Cols = 2 */
+#define SWRM_DEFAULT_COL 16
+#define SWRM_MAX_COL_VAL 7
+#define SWRM_SPECIAL_CMD_ID 0xF
+#define MAX_FREQ_NUM 1
+#define TIMEOUT_MS (2 * HZ)
+#define QCOM_SWRM_MAX_RD_LEN 0xf
+#define QCOM_SDW_MAX_PORTS 14
+#define DEFAULT_CLK_FREQ 9600000
+#define SWRM_MAX_DAIS 0xF
+
+struct qcom_swrm_port_config {
+ u8 si;
+ u8 off1;
+ u8 off2;
+};
+
+struct qcom_swrm_ctrl {
+ struct sdw_bus bus;
+ struct device *dev;
+ struct regmap *regmap;
+ struct completion *comp;
+ struct work_struct slave_work;
+ /* read/write lock */
+ spinlock_t comp_lock;
+ /* Port alloc/free lock */
+ struct mutex port_lock;
+ struct clk *hclk;
+ u8 wr_cmd_id;
+ u8 rd_cmd_id;
+ int irq;
+ unsigned int version;
+ int num_din_ports;
+ int num_dout_ports;
+ unsigned long dout_port_mask;
+ unsigned long din_port_mask;
+ struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS];
+ struct sdw_stream_runtime *sruntime[SWRM_MAX_DAIS];
+ enum sdw_slave_status status[SDW_MAX_DEVICES];
+ int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val);
+ int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val);
+};
+
+#define to_qcom_sdw(b) container_of(b, struct qcom_swrm_ctrl, bus)
+
+static int qcom_swrm_abh_reg_read(struct qcom_swrm_ctrl *ctrl, int reg,
+ u32 *val)
+{
+ struct regmap *wcd_regmap = ctrl->regmap;
+ int ret;
+
+ /* pg register + offset */
+ ret = regmap_bulk_write(wcd_regmap, SWRM_AHB_BRIDGE_RD_ADDR_0,
+ (u8 *)&reg, 4);
+ if (ret < 0)
+ return SDW_CMD_FAIL;
+
+ ret = regmap_bulk_read(wcd_regmap, SWRM_AHB_BRIDGE_RD_DATA_0,
+ val, 4);
+ if (ret < 0)
+ return SDW_CMD_FAIL;
+
+ return SDW_CMD_OK;
+}
+
+static int qcom_swrm_ahb_reg_write(struct qcom_swrm_ctrl *ctrl,
+ int reg, int val)
+{
+ struct regmap *wcd_regmap = ctrl->regmap;
+ int ret;
+ /* pg register + offset */
+ ret = regmap_bulk_write(wcd_regmap, SWRM_AHB_BRIDGE_WR_DATA_0,
+ (u8 *)&val, 4);
+ if (ret)
+ return SDW_CMD_FAIL;
+
+ /* write address register */
+ ret = regmap_bulk_write(wcd_regmap, SWRM_AHB_BRIDGE_WR_ADDR_0,
+ (u8 *)&reg, 4);
+ if (ret)
+ return SDW_CMD_FAIL;
+
+ return SDW_CMD_OK;
+}
+
+static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl *ctrl, u8 cmd_data,
+ u8 dev_addr, u16 reg_addr)
+{
+ DECLARE_COMPLETION_ONSTACK(comp);
+ unsigned long flags;
+ u32 val;
+ int ret;
+
+ spin_lock_irqsave(&ctrl->comp_lock, flags);
+ ctrl->comp = &comp;
+ spin_unlock_irqrestore(&ctrl->comp_lock, flags);
+ val = SWRM_REG_VAL_PACK(cmd_data, dev_addr,
+ SWRM_SPECIAL_CMD_ID, reg_addr);
+ ret = ctrl->reg_write(ctrl, SWRM_CMD_FIFO_WR_CMD, val);
+ if (ret)
+ goto err;
+
+ ret = wait_for_completion_timeout(ctrl->comp,
+ msecs_to_jiffies(TIMEOUT_MS));
+
+ if (!ret)
+ ret = SDW_CMD_IGNORED;
+ else
+ ret = SDW_CMD_OK;
+err:
+ spin_lock_irqsave(&ctrl->comp_lock, flags);
+ ctrl->comp = NULL;
+ spin_unlock_irqrestore(&ctrl->comp_lock, flags);
+
+ return ret;
+}
+
+static int qcom_swrm_cmd_fifo_rd_cmd(struct qcom_swrm_ctrl *ctrl,
+ u8 dev_addr, u16 reg_addr,
+ u32 len, u8 *rval)
+{
+ int i, ret;
+ u32 val;
+ DECLARE_COMPLETION_ONSTACK(comp);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctrl->comp_lock, flags);
+ ctrl->comp = &comp;
+ spin_unlock_irqrestore(&ctrl->comp_lock, flags);
+
+ val = SWRM_REG_VAL_PACK(len, dev_addr, SWRM_SPECIAL_CMD_ID, reg_addr);
+ ret = ctrl->reg_write(ctrl, SWRM_CMD_FIFO_RD_CMD, val);
+ if (ret)
+ goto err;
+
+ ret = wait_for_completion_timeout(ctrl->comp,
+ msecs_to_jiffies(TIMEOUT_MS));
+
+ if (!ret) {
+ ret = SDW_CMD_IGNORED;
+ goto err;
+ } else {
+ ret = SDW_CMD_OK;
+ }
+
+ for (i = 0; i < len; i++) {
+ ctrl->reg_read(ctrl, SWRM_CMD_FIFO_RD_FIFO_ADDR, &val);
+ rval[i] = val & 0xFF;
+ }
+
+err:
+ spin_lock_irqsave(&ctrl->comp_lock, flags);
+ ctrl->comp = NULL;
+ spin_unlock_irqrestore(&ctrl->comp_lock, flags);
+
+ return ret;
+}
+
+static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl)
+{
+ u32 val;
+ int i;
+
+ ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val);
+
+ for (i = 0; i < SDW_MAX_DEVICES; i++) {
+ u32 s;
+
+ s = (val >> (i * 2));
+ s &= SWRM_MCP_SLV_STATUS_MASK;
+ ctrl->status[i] = s;
+ }
+}
+
+static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id)
+{
+ struct qcom_swrm_ctrl *ctrl = dev_id;
+ u32 sts, value;
+ unsigned long flags;
+
+ ctrl->reg_read(ctrl, SWRM_INTERRUPT_STATUS, &sts);
+
+ if (sts & SWRM_INTERRUPT_STATUS_CMD_ERROR) {
+ ctrl->reg_read(ctrl, SWRM_CMD_FIFO_STATUS, &value);
+ dev_err_ratelimited(ctrl->dev,
+ "CMD error, fifo status 0x%x\n",
+ value);
+ ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CMD, 0x1);
+ }
+
+ if ((sts & SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED) ||
+ sts & SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS)
+ schedule_work(&ctrl->slave_work);
+
+ /**
+ * clear the interrupt before complete() is called, as complete can
+ * schedule new read/writes which require interrupts, clearing the
+ * interrupt would avoid missing interrupts in such cases.
+ */
+ ctrl->reg_write(ctrl, SWRM_INTERRUPT_CLEAR, sts);
+
+ if (sts & SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED) {
+ spin_lock_irqsave(&ctrl->comp_lock, flags);
+ if (ctrl->comp)
+ complete(ctrl->comp);
+ spin_unlock_irqrestore(&ctrl->comp_lock, flags);
+ }
+
+ return IRQ_HANDLED;
+}
+static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
+{
+ u32 val;
+
+ /* Clear Rows and Cols */
+ val = (SWRM_MAX_ROW_VAL << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT |
+ SWRM_MIN_COL_VAL << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT);
+
+ ctrl->reg_write(ctrl, SWRM_MCP_FRAME_CTRL_BANK_ADDR(0), val);
+
+ /* Disable Auto enumeration */
+ ctrl->reg_write(ctrl, SWRM_ENUMERATOR_CFG_ADDR, 0);
+
+ /* Mask soundwire interrupts */
+ ctrl->reg_write(ctrl, SWRM_INTERRUPT_MASK_ADDR,
+ SWRM_INTERRUPT_STATUS_RMSK);
+
+ /* Configure No pings */
+ ctrl->reg_read(ctrl, SWRM_MCP_CFG_ADDR, &val);
+ val &= ~SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK;
+ val |= (SWRM_DEF_CMD_NO_PINGS <<
+ SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_SHFT);
+ ctrl->reg_write(ctrl, SWRM_MCP_CFG_ADDR, val);
+
+ /* Configure number of retries of a read/write cmd */
+ ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR, SWRM_RD_WR_CMD_RETRIES);
+
+ /* Set IRQ to PULSE */
+ ctrl->reg_write(ctrl, SWRM_COMP_CFG_ADDR,
+ SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK |
+ SWRM_COMP_CFG_ENABLE_MSK);
+ return 0;
+}
+
+static enum sdw_command_response qcom_swrm_xfer_msg(struct sdw_bus *bus,
+ struct sdw_msg *msg)
+{
+ struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
+ int ret, i, len;
+
+ if (msg->flags == SDW_MSG_FLAG_READ) {
+ for (i = 0; i < msg->len;) {
+ if ((msg->len - i) < QCOM_SWRM_MAX_RD_LEN)
+ len = msg->len - i;
+ else
+ len = QCOM_SWRM_MAX_RD_LEN;
+
+ ret = qcom_swrm_cmd_fifo_rd_cmd(ctrl, msg->dev_num,
+ msg->addr + i, len,
+ &msg->buf[i]);
+ if (ret)
+ return ret;
+
+ i = i + len;
+ }
+ } else if (msg->flags == SDW_MSG_FLAG_WRITE) {
+ for (i = 0; i < msg->len; i++) {
+ ret = qcom_swrm_cmd_fifo_wr_cmd(ctrl, msg->buf[i],
+ msg->dev_num,
+ msg->addr + i);
+ if (ret)
+ return SDW_CMD_IGNORED;
+ }
+ }
+
+ return SDW_CMD_OK;
+}
+
+static int qcom_swrm_pre_bank_switch(struct sdw_bus *bus)
+{
+ u32 reg = SWRM_MCP_FRAME_CTRL_BANK_ADDR(bus->params.next_bank);
+ struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
+ u32 val;
+
+ ctrl->reg_read(ctrl, reg, &val);
+
+ val &= ~SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK;
+ val &= ~SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK;
+
+ val |= (SWRM_MAX_ROW_VAL << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT |
+ SWRM_MAX_COL_VAL << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT);
+
+ return ctrl->reg_write(ctrl, reg, val);
+}
+
+static int qcom_swrm_port_params(struct sdw_bus *bus,
+ struct sdw_port_params *p_params,
+ unsigned int bank)
+{
+ /* TBD */
+ return 0;
+}
+
+static int qcom_swrm_transport_params(struct sdw_bus *bus,
+ struct sdw_transport_params *params,
+ enum sdw_reg_bank bank)
+{
+ struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
+ u32 value;
+
+ value = params->offset1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT;
+ value |= params->offset2 << SWRM_DP_PORT_CTRL_OFFSET2_SHFT;
+ value |= params->sample_interval - 1;
+
+ return ctrl->reg_write(ctrl,
+ SWRM_DP_PORT_CTRL_BANK((params->port_num), bank),
+ value);
+}
+
+static int qcom_swrm_port_enable(struct sdw_bus *bus,
+ struct sdw_enable_ch *enable_ch,
+ unsigned int bank)
+{
+ u32 reg = SWRM_DP_PORT_CTRL_BANK(enable_ch->port_num, bank);
+ struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
+ u32 val;
+
+ ctrl->reg_read(ctrl, reg, &val);
+
+ if (enable_ch->enable)
+ val |= (enable_ch->ch_mask << SWRM_DP_PORT_CTRL_EN_CHAN_SHFT);
+ else
+ val &= ~(0xff << SWRM_DP_PORT_CTRL_EN_CHAN_SHFT);
+
+ return ctrl->reg_write(ctrl, reg, val);
+}
+
+static struct sdw_master_port_ops qcom_swrm_port_ops = {
+ .dpn_set_port_params = qcom_swrm_port_params,
+ .dpn_set_port_transport_params = qcom_swrm_transport_params,
+ .dpn_port_enable_ch = qcom_swrm_port_enable,
+};
+
+static struct sdw_master_ops qcom_swrm_ops = {
+ .xfer_msg = qcom_swrm_xfer_msg,
+ .pre_bank_switch = qcom_swrm_pre_bank_switch,
+};
+
+static int qcom_swrm_compute_params(struct sdw_bus *bus)
+{
+ struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
+ struct sdw_master_runtime *m_rt;
+ struct sdw_slave_runtime *s_rt;
+ struct sdw_port_runtime *p_rt;
+ struct qcom_swrm_port_config *pcfg;
+ int i = 0;
+
+ list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
+ list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
+ pcfg = &ctrl->pconfig[p_rt->num - 1];
+ p_rt->transport_params.port_num = p_rt->num;
+ p_rt->transport_params.sample_interval = pcfg->si + 1;
+ p_rt->transport_params.offset1 = pcfg->off1;
+ p_rt->transport_params.offset2 = pcfg->off2;
+ }
+
+ list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
+ list_for_each_entry(p_rt, &s_rt->port_list, port_node) {
+ pcfg = &ctrl->pconfig[i];
+ p_rt->transport_params.port_num = p_rt->num;
+ p_rt->transport_params.sample_interval =
+ pcfg->si + 1;
+ p_rt->transport_params.offset1 = pcfg->off1;
+ p_rt->transport_params.offset2 = pcfg->off2;
+ i++;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static u32 qcom_swrm_freq_tbl[MAX_FREQ_NUM] = {
+ DEFAULT_CLK_FREQ,
+};
+
+static void qcom_swrm_slave_wq(struct work_struct *work)
+{
+ struct qcom_swrm_ctrl *ctrl =
+ container_of(work, struct qcom_swrm_ctrl, slave_work);
+
+ qcom_swrm_get_device_status(ctrl);
+ sdw_handle_slave_status(&ctrl->bus, ctrl->status);
+}
+
+
+static void qcom_swrm_stream_free_ports(struct qcom_swrm_ctrl *ctrl,
+ struct sdw_stream_runtime *stream)
+{
+ struct sdw_master_runtime *m_rt;
+ struct sdw_port_runtime *p_rt;
+ unsigned long *port_mask;
+
+ mutex_lock(&ctrl->port_lock);
+
+ list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+ if (m_rt->direction == SDW_DATA_DIR_RX)
+ port_mask = &ctrl->dout_port_mask;
+ else
+ port_mask = &ctrl->din_port_mask;
+
+ list_for_each_entry(p_rt, &m_rt->port_list, port_node)
+ clear_bit(p_rt->num - 1, port_mask);
+ }
+
+ mutex_unlock(&ctrl->port_lock);
+}
+
+static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl,
+ struct sdw_stream_runtime *stream,
+ struct snd_pcm_hw_params *params,
+ int direction)
+{
+ struct sdw_port_config pconfig[QCOM_SDW_MAX_PORTS];
+ struct sdw_stream_config sconfig;
+ struct sdw_master_runtime *m_rt;
+ struct sdw_slave_runtime *s_rt;
+ struct sdw_port_runtime *p_rt;
+ unsigned long *port_mask;
+ int i, maxport, pn, nports = 0, ret = 0;
+
+ mutex_lock(&ctrl->port_lock);
+ list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+ if (m_rt->direction == SDW_DATA_DIR_RX) {
+ maxport = ctrl->num_dout_ports;
+ port_mask = &ctrl->dout_port_mask;
+ } else {
+ maxport = ctrl->num_din_ports;
+ port_mask = &ctrl->din_port_mask;
+ }
+
+ list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
+ list_for_each_entry(p_rt, &s_rt->port_list, port_node) {
+ /* Port numbers start from 1 - 14*/
+ pn = find_first_zero_bit(port_mask, maxport);
+ if (pn > (maxport - 1)) {
+ dev_err(ctrl->dev, "All ports busy\n");
+ ret = -EBUSY;
+ goto err;
+ }
+ set_bit(pn, port_mask);
+ pconfig[nports].num = pn + 1;
+ pconfig[nports].ch_mask = p_rt->ch_mask;
+ nports++;
+ }
+ }
+ }
+
+ if (direction == SNDRV_PCM_STREAM_CAPTURE)
+ sconfig.direction = SDW_DATA_DIR_TX;
+ else
+ sconfig.direction = SDW_DATA_DIR_RX;
+
+ /* hw parameters wil be ignored as we only support PDM */
+ sconfig.ch_count = 1;
+ sconfig.frame_rate = params_rate(params);
+ sconfig.type = stream->type;
+ sconfig.bps = 1;
+ sdw_stream_add_master(&ctrl->bus, &sconfig, pconfig,
+ nports, stream);
+err:
+ if (ret) {
+ for (i = 0; i < nports; i++)
+ clear_bit(pconfig[i].num - 1, port_mask);
+ }
+
+ mutex_unlock(&ctrl->port_lock);
+
+ return ret;
+}
+
+static int qcom_swrm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev);
+ struct sdw_stream_runtime *sruntime = ctrl->sruntime[dai->id];
+ int ret;
+
+ ret = qcom_swrm_stream_alloc_ports(ctrl, sruntime, params,
+ substream->stream);
+ if (ret)
+ qcom_swrm_stream_free_ports(ctrl, sruntime);
+
+ return ret;
+}
+
+static int qcom_swrm_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev);
+ struct sdw_stream_runtime *sruntime = ctrl->sruntime[dai->id];
+
+ qcom_swrm_stream_free_ports(ctrl, sruntime);
+ sdw_stream_remove_master(&ctrl->bus, sruntime);
+
+ return 0;
+}
+
+static int qcom_swrm_set_sdw_stream(struct snd_soc_dai *dai,
+ void *stream, int direction)
+{
+ struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev);
+
+ ctrl->sruntime[dai->id] = stream;
+
+ return 0;
+}
+
+static int qcom_swrm_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev);
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct sdw_stream_runtime *sruntime;
+ int ret, i;
+
+ sruntime = sdw_alloc_stream(dai->name);
+ if (!sruntime)
+ return -ENOMEM;
+
+ ctrl->sruntime[dai->id] = sruntime;
+
+ for (i = 0; i < rtd->num_codecs; i++) {
+ ret = snd_soc_dai_set_sdw_stream(rtd->codec_dais[i], sruntime,
+ substream->stream);
+ if (ret < 0 && ret != -ENOTSUPP) {
+ dev_err(dai->dev, "Failed to set sdw stream on %s",
+ rtd->codec_dais[i]->name);
+ sdw_release_stream(sruntime);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void qcom_swrm_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev);
+
+ sdw_release_stream(ctrl->sruntime[dai->id]);
+ ctrl->sruntime[dai->id] = NULL;
+}
+
+static const struct snd_soc_dai_ops qcom_swrm_pdm_dai_ops = {
+ .hw_params = qcom_swrm_hw_params,
+ .hw_free = qcom_swrm_hw_free,
+ .startup = qcom_swrm_startup,
+ .shutdown = qcom_swrm_shutdown,
+ .set_sdw_stream = qcom_swrm_set_sdw_stream,
+};
+
+static const struct snd_soc_component_driver qcom_swrm_dai_component = {
+ .name = "soundwire",
+};
+
+static int qcom_swrm_register_dais(struct qcom_swrm_ctrl *ctrl)
+{
+ int num_dais = ctrl->num_dout_ports + ctrl->num_din_ports;
+ struct snd_soc_dai_driver *dais;
+ struct snd_soc_pcm_stream *stream;
+ struct device *dev = ctrl->dev;
+ int i;
+
+ /* PDM dais are only tested for now */
+ dais = devm_kcalloc(dev, num_dais, sizeof(*dais), GFP_KERNEL);
+ if (!dais)
+ return -ENOMEM;
+
+ for (i = 0; i < num_dais; i++) {
+ dais[i].name = devm_kasprintf(dev, GFP_KERNEL, "SDW Pin%d", i);
+ if (!dais[i].name)
+ return -ENOMEM;
+
+ if (i < ctrl->num_dout_ports)
+ stream = &dais[i].playback;
+ else
+ stream = &dais[i].capture;
+
+ stream->channels_min = 1;
+ stream->channels_max = 1;
+ stream->rates = SNDRV_PCM_RATE_48000;
+ stream->formats = SNDRV_PCM_FMTBIT_S16_LE;
+
+ dais[i].ops = &qcom_swrm_pdm_dai_ops;
+ dais[i].id = i;
+ }
+
+ return devm_snd_soc_register_component(ctrl->dev,
+ &qcom_swrm_dai_component,
+ dais, num_dais);
+}
+
+static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl)
+{
+ struct device_node *np = ctrl->dev->of_node;
+ u8 off1[QCOM_SDW_MAX_PORTS];
+ u8 off2[QCOM_SDW_MAX_PORTS];
+ u8 si[QCOM_SDW_MAX_PORTS];
+ int i, ret, nports, val;
+
+ ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val);
+
+ ctrl->num_dout_ports = val & SWRM_COMP_PARAMS_DOUT_PORTS_MASK;
+ ctrl->num_din_ports = (val & SWRM_COMP_PARAMS_DIN_PORTS_MASK) >> 5;
+
+ ret = of_property_read_u32(np, "qcom,din-ports", &val);
+ if (ret)
+ return ret;
+
+ if (val > ctrl->num_din_ports)
+ return -EINVAL;
+
+ ctrl->num_din_ports = val;
+
+ ret = of_property_read_u32(np, "qcom,dout-ports", &val);
+ if (ret)
+ return ret;
+
+ if (val > ctrl->num_dout_ports)
+ return -EINVAL;
+
+ ctrl->num_dout_ports = val;
+
+ nports = ctrl->num_dout_ports + ctrl->num_din_ports;
+
+ ret = of_property_read_u8_array(np, "qcom,ports-offset1",
+ off1, nports);
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u8_array(np, "qcom,ports-offset2",
+ off2, nports);
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u8_array(np, "qcom,ports-sinterval-low",
+ si, nports);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < nports; i++) {
+ ctrl->pconfig[i].si = si[i];
+ ctrl->pconfig[i].off1 = off1[i];
+ ctrl->pconfig[i].off2 = off2[i];
+ }
+
+ return 0;
+}
+
+static int qcom_swrm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct sdw_master_prop *prop;
+ struct sdw_bus_params *params;
+ struct qcom_swrm_ctrl *ctrl;
+ int ret;
+ u32 val;
+
+ ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
+ if (!ctrl)
+ return -ENOMEM;
+
+ if (dev->parent->bus == &slimbus_bus) {
+ ctrl->reg_read = qcom_swrm_abh_reg_read;
+ ctrl->reg_write = qcom_swrm_ahb_reg_write;
+ ctrl->regmap = dev_get_regmap(dev->parent, NULL);
+ if (!ctrl->regmap)
+ return -EINVAL;
+ } else {
+ /* Only WCD based SoundWire controller is supported */
+ return -ENOTSUPP;
+ }
+
+ ctrl->irq = of_irq_get(dev->of_node, 0);
+ if (ctrl->irq < 0)
+ return ctrl->irq;
+
+ ctrl->hclk = devm_clk_get(dev, "iface");
+ if (IS_ERR(ctrl->hclk))
+ return PTR_ERR(ctrl->hclk);
+
+ clk_prepare_enable(ctrl->hclk);
+
+ ctrl->dev = dev;
+ dev_set_drvdata(&pdev->dev, ctrl);
+ spin_lock_init(&ctrl->comp_lock);
+ mutex_init(&ctrl->port_lock);
+ INIT_WORK(&ctrl->slave_work, qcom_swrm_slave_wq);
+
+ ctrl->bus.dev = dev;
+ ctrl->bus.ops = &qcom_swrm_ops;
+ ctrl->bus.port_ops = &qcom_swrm_port_ops;
+ ctrl->bus.compute_params = &qcom_swrm_compute_params;
+
+ ret = qcom_swrm_get_port_config(ctrl);
+ if (ret)
+ return ret;
+
+ params = &ctrl->bus.params;
+ params->max_dr_freq = DEFAULT_CLK_FREQ;
+ params->curr_dr_freq = DEFAULT_CLK_FREQ;
+ params->col = SWRM_DEFAULT_COL;
+ params->row = SWRM_DEFAULT_ROWS;
+ ctrl->reg_read(ctrl, SWRM_MCP_STATUS, &val);
+ params->curr_bank = val & SWRM_MCP_STATUS_BANK_NUM_MASK;
+ params->next_bank = !params->curr_bank;
+
+ prop = &ctrl->bus.prop;
+ prop->max_clk_freq = DEFAULT_CLK_FREQ;
+ prop->num_clk_gears = 0;
+ prop->num_clk_freq = MAX_FREQ_NUM;
+ prop->clk_freq = &qcom_swrm_freq_tbl[0];
+ prop->default_col = SWRM_DEFAULT_COL;
+ prop->default_row = SWRM_DEFAULT_ROWS;
+
+ ctrl->reg_read(ctrl, SWRM_COMP_HW_VERSION, &ctrl->version);
+
+ ret = devm_request_threaded_irq(dev, ctrl->irq, NULL,
+ qcom_swrm_irq_handler,
+ IRQF_TRIGGER_RISING,
+ "soundwire", ctrl);
+ if (ret) {
+ dev_err(dev, "Failed to request soundwire irq\n");
+ goto err;
+ }
+
+ ret = sdw_add_bus_master(&ctrl->bus);
+ if (ret) {
+ dev_err(dev, "Failed to register Soundwire controller (%d)\n",
+ ret);
+ goto err;
+ }
+
+ qcom_swrm_init(ctrl);
+ ret = qcom_swrm_register_dais(ctrl);
+ if (ret)
+ goto err;
+
+ dev_info(dev, "Qualcomm Soundwire controller v%x.%x.%x Registered\n",
+ (ctrl->version >> 24) & 0xff, (ctrl->version >> 16) & 0xff,
+ ctrl->version & 0xffff);
+
+ return 0;
+err:
+ clk_disable_unprepare(ctrl->hclk);
+ return ret;
+}
+
+static int qcom_swrm_remove(struct platform_device *pdev)
+{
+ struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(&pdev->dev);
+
+ sdw_delete_bus_master(&ctrl->bus);
+ clk_disable_unprepare(ctrl->hclk);
+
+ return 0;
+}
+
+static const struct of_device_id qcom_swrm_of_match[] = {
+ { .compatible = "qcom,soundwire-v1.3.0", },
+ {/* sentinel */},
+};
+
+MODULE_DEVICE_TABLE(of, qcom_swrm_of_match);
+
+static struct platform_driver qcom_swrm_driver = {
+ .probe = &qcom_swrm_probe,
+ .remove = &qcom_swrm_remove,
+ .driver = {
+ .name = "qcom-soundwire",
+ .of_match_table = qcom_swrm_of_match,
+ }
+};
+module_platform_driver(qcom_swrm_driver);
+
+MODULE_DESCRIPTION("Qualcomm soundwire driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
index e69f94a8c3a8..178ae92b8cc1 100644
--- a/drivers/soundwire/stream.c
+++ b/drivers/soundwire/stream.c
@@ -1554,8 +1554,6 @@ int sdw_prepare_stream(struct sdw_stream_runtime *stream)
sdw_acquire_bus_lock(stream);
ret = _sdw_prepare_stream(stream);
- if (ret < 0)
- pr_err("Prepare for stream:%s failed: %d\n", stream->name, ret);
sdw_release_bus_lock(stream);
return ret;
@@ -1622,8 +1620,6 @@ int sdw_enable_stream(struct sdw_stream_runtime *stream)
sdw_acquire_bus_lock(stream);
ret = _sdw_enable_stream(stream);
- if (ret < 0)
- pr_err("Enable for stream:%s failed: %d\n", stream->name, ret);
sdw_release_bus_lock(stream);
return ret;
@@ -1698,8 +1694,6 @@ int sdw_disable_stream(struct sdw_stream_runtime *stream)
sdw_acquire_bus_lock(stream);
ret = _sdw_disable_stream(stream);
- if (ret < 0)
- pr_err("Disable for stream:%s failed: %d\n", stream->name, ret);
sdw_release_bus_lock(stream);
return ret;
@@ -1756,8 +1750,6 @@ int sdw_deprepare_stream(struct sdw_stream_runtime *stream)
sdw_acquire_bus_lock(stream);
ret = _sdw_deprepare_stream(stream);
- if (ret < 0)
- pr_err("De-prepare for stream:%d failed: %d\n", ret, ret);
sdw_release_bus_lock(stream);
return ret;
diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c
index 81c88f7bbbcb..f6ab3f28c838 100644
--- a/drivers/uio/uio_dmem_genirq.c
+++ b/drivers/uio/uio_dmem_genirq.c
@@ -132,11 +132,13 @@ static int uio_dmem_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on)
if (irq_on) {
if (test_and_clear_bit(0, &priv->flags))
enable_irq(dev_info->irq);
+ spin_unlock_irqrestore(&priv->lock, flags);
} else {
- if (!test_and_set_bit(0, &priv->flags))
+ if (!test_and_set_bit(0, &priv->flags)) {
+ spin_unlock_irqrestore(&priv->lock, flags);
disable_irq(dev_info->irq);
+ }
}
- spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c
index 1303b165055b..fc25ce90da3b 100644
--- a/drivers/uio/uio_pdrv_genirq.c
+++ b/drivers/uio/uio_pdrv_genirq.c
@@ -156,6 +156,8 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev)
uioinfo->irq = ret;
if (ret == -ENXIO && pdev->dev.of_node)
uioinfo->irq = UIO_IRQ_NONE;
+ else if (ret == -EPROBE_DEFER)
+ return ret;
else if (ret < 0) {
dev_err(&pdev->dev, "failed to get IRQ\n");
return ret;
diff --git a/drivers/visorbus/visorchipset.c b/drivers/visorbus/visorchipset.c
index ca752b8f495f..cb1eb7e05f87 100644
--- a/drivers/visorbus/visorchipset.c
+++ b/drivers/visorbus/visorchipset.c
@@ -1210,14 +1210,17 @@ static void setup_crash_devices_work_queue(struct work_struct *work)
{
struct controlvm_message local_crash_bus_msg;
struct controlvm_message local_crash_dev_msg;
- struct controlvm_message msg;
+ struct controlvm_message msg = {
+ .hdr.id = CONTROLVM_CHIPSET_INIT,
+ .cmd.init_chipset = {
+ .bus_count = 23,
+ .switch_count = 0,
+ },
+ };
u32 local_crash_msg_offset;
u16 local_crash_msg_count;
/* send init chipset msg */
- msg.hdr.id = CONTROLVM_CHIPSET_INIT;
- msg.cmd.init_chipset.bus_count = 23;
- msg.cmd.init_chipset.switch_count = 0;
chipset_init(&msg);
/* get saved message count */
if (visorchannel_read(chipset_dev->controlvm_channel,
diff --git a/drivers/vme/bridges/vme_fake.c b/drivers/vme/bridges/vme_fake.c
index 3208a4409e44..6a1bc284f297 100644
--- a/drivers/vme/bridges/vme_fake.c
+++ b/drivers/vme/bridges/vme_fake.c
@@ -414,8 +414,9 @@ static void fake_lm_check(struct fake_driver *bridge, unsigned long long addr,
}
}
-static u8 fake_vmeread8(struct fake_driver *bridge, unsigned long long addr,
- u32 aspace, u32 cycle)
+static noinline_for_stack u8 fake_vmeread8(struct fake_driver *bridge,
+ unsigned long long addr,
+ u32 aspace, u32 cycle)
{
u8 retval = 0xff;
int i;
@@ -446,8 +447,9 @@ static u8 fake_vmeread8(struct fake_driver *bridge, unsigned long long addr,
return retval;
}
-static u16 fake_vmeread16(struct fake_driver *bridge, unsigned long long addr,
- u32 aspace, u32 cycle)
+static noinline_for_stack u16 fake_vmeread16(struct fake_driver *bridge,
+ unsigned long long addr,
+ u32 aspace, u32 cycle)
{
u16 retval = 0xffff;
int i;
@@ -478,8 +480,9 @@ static u16 fake_vmeread16(struct fake_driver *bridge, unsigned long long addr,
return retval;
}
-static u32 fake_vmeread32(struct fake_driver *bridge, unsigned long long addr,
- u32 aspace, u32 cycle)
+static noinline_for_stack u32 fake_vmeread32(struct fake_driver *bridge,
+ unsigned long long addr,
+ u32 aspace, u32 cycle)
{
u32 retval = 0xffffffff;
int i;
@@ -609,8 +612,9 @@ out:
return retval;
}
-static void fake_vmewrite8(struct fake_driver *bridge, u8 *buf,
- unsigned long long addr, u32 aspace, u32 cycle)
+static noinline_for_stack void fake_vmewrite8(struct fake_driver *bridge,
+ u8 *buf, unsigned long long addr,
+ u32 aspace, u32 cycle)
{
int i;
unsigned long long start, end, offset;
@@ -639,8 +643,9 @@ static void fake_vmewrite8(struct fake_driver *bridge, u8 *buf,
}
-static void fake_vmewrite16(struct fake_driver *bridge, u16 *buf,
- unsigned long long addr, u32 aspace, u32 cycle)
+static noinline_for_stack void fake_vmewrite16(struct fake_driver *bridge,
+ u16 *buf, unsigned long long addr,
+ u32 aspace, u32 cycle)
{
int i;
unsigned long long start, end, offset;
@@ -669,8 +674,9 @@ static void fake_vmewrite16(struct fake_driver *bridge, u16 *buf,
}
-static void fake_vmewrite32(struct fake_driver *bridge, u32 *buf,
- unsigned long long addr, u32 aspace, u32 cycle)
+static noinline_for_stack void fake_vmewrite32(struct fake_driver *bridge,
+ u32 *buf, unsigned long long addr,
+ u32 aspace, u32 cycle)
{
int i;
unsigned long long start, end, offset;
diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c
index 4164045866b3..aa09f8527776 100644
--- a/drivers/w1/masters/omap_hdq.c
+++ b/drivers/w1/masters/omap_hdq.c
@@ -38,12 +38,6 @@
#define OMAP_HDQ_INT_STATUS_TXCOMPLETE BIT(2)
#define OMAP_HDQ_INT_STATUS_RXCOMPLETE BIT(1)
#define OMAP_HDQ_INT_STATUS_TIMEOUT BIT(0)
-#define OMAP_HDQ_SYSCONFIG 0x14
-#define OMAP_HDQ_SYSCONFIG_SOFTRESET BIT(1)
-#define OMAP_HDQ_SYSCONFIG_AUTOIDLE BIT(0)
-#define OMAP_HDQ_SYSCONFIG_NOIDLE 0x0
-#define OMAP_HDQ_SYSSTATUS 0x18
-#define OMAP_HDQ_SYSSTATUS_RESETDONE BIT(0)
#define OMAP_HDQ_FLAG_CLEAR 0
#define OMAP_HDQ_FLAG_SET 1
@@ -62,17 +56,9 @@ struct hdq_data {
void __iomem *hdq_base;
/* lock status update */
struct mutex hdq_mutex;
- int hdq_usecount;
u8 hdq_irqstatus;
/* device lock */
spinlock_t hdq_spinlock;
- /*
- * Used to control the call to omap_hdq_get and omap_hdq_put.
- * HDQ Protocol: Write the CMD|REG_address first, followed by
- * the data wrire or read.
- */
- int init_trans;
- int rrw;
/* mode: 0-HDQ 1-W1 */
int mode;
@@ -99,15 +85,6 @@ static inline u8 hdq_reg_merge(struct hdq_data *hdq_data, u32 offset,
return new_val;
}
-static void hdq_disable_interrupt(struct hdq_data *hdq_data, u32 offset,
- u32 mask)
-{
- u32 ie;
-
- ie = readl(hdq_data->hdq_base + offset);
- writel(ie & mask, hdq_data->hdq_base + offset);
-}
-
/*
* Wait for one or more bits in flag change.
* HDQ_FLAG_SET: wait until any bit in the flag is set.
@@ -142,22 +119,24 @@ static int hdq_wait_for_flag(struct hdq_data *hdq_data, u32 offset,
return ret;
}
+/* Clear saved irqstatus after using an interrupt */
+static void hdq_reset_irqstatus(struct hdq_data *hdq_data)
+{
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
+ hdq_data->hdq_irqstatus = 0;
+ spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
+}
+
/* write out a byte and fill *status with HDQ_INT_STATUS */
static int hdq_write_byte(struct hdq_data *hdq_data, u8 val, u8 *status)
{
int ret;
u8 tmp_status;
- unsigned long irqflags;
*status = 0;
- spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
- /* clear interrupt flags via a dummy read */
- hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
- /* ISR loads it with new INT_STATUS */
- hdq_data->hdq_irqstatus = 0;
- spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
-
hdq_reg_out(hdq_data, OMAP_HDQ_TX_DATA, val);
/* set the GO bit */
@@ -191,6 +170,7 @@ static int hdq_write_byte(struct hdq_data *hdq_data, u8 val, u8 *status)
}
out:
+ hdq_reset_irqstatus(hdq_data);
return ret;
}
@@ -237,47 +217,11 @@ static void omap_w1_search_bus(void *_hdq, struct w1_master *master_dev,
slave_found(master_dev, id);
}
-static int _omap_hdq_reset(struct hdq_data *hdq_data)
-{
- int ret;
- u8 tmp_status;
-
- hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG,
- OMAP_HDQ_SYSCONFIG_SOFTRESET);
- /*
- * Select HDQ/1W mode & enable clocks.
- * It is observed that INT flags can't be cleared via a read and GO/INIT
- * won't return to zero if interrupt is disabled. So we always enable
- * interrupt.
- */
- hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS,
- OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
- OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK);
-
- /* wait for reset to complete */
- ret = hdq_wait_for_flag(hdq_data, OMAP_HDQ_SYSSTATUS,
- OMAP_HDQ_SYSSTATUS_RESETDONE, OMAP_HDQ_FLAG_SET, &tmp_status);
- if (ret)
- dev_dbg(hdq_data->dev, "timeout waiting HDQ reset, %x",
- tmp_status);
- else {
- hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS,
- OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
- OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK |
- hdq_data->mode);
- hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG,
- OMAP_HDQ_SYSCONFIG_AUTOIDLE);
- }
-
- return ret;
-}
-
/* Issue break pulse to the device */
static int omap_hdq_break(struct hdq_data *hdq_data)
{
int ret = 0;
u8 tmp_status;
- unsigned long irqflags;
ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
if (ret < 0) {
@@ -286,13 +230,6 @@ static int omap_hdq_break(struct hdq_data *hdq_data)
goto rtn;
}
- spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
- /* clear interrupt flags via a dummy read */
- hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
- /* ISR loads it with new INT_STATUS */
- hdq_data->hdq_irqstatus = 0;
- spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
-
/* set the INIT and GO bit */
hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS,
OMAP_HDQ_CTRL_STATUS_INITIALIZATION | OMAP_HDQ_CTRL_STATUS_GO,
@@ -341,6 +278,7 @@ static int omap_hdq_break(struct hdq_data *hdq_data)
" return to zero, %x", tmp_status);
out:
+ hdq_reset_irqstatus(hdq_data);
mutex_unlock(&hdq_data->hdq_mutex);
rtn:
return ret;
@@ -357,7 +295,7 @@ static int hdq_read_byte(struct hdq_data *hdq_data, u8 *val)
goto rtn;
}
- if (!hdq_data->hdq_usecount) {
+ if (pm_runtime_suspended(hdq_data->dev)) {
ret = -EINVAL;
goto out;
}
@@ -388,86 +326,13 @@ static int hdq_read_byte(struct hdq_data *hdq_data, u8 *val)
/* the data is ready. Read it in! */
*val = hdq_reg_in(hdq_data, OMAP_HDQ_RX_DATA);
out:
+ hdq_reset_irqstatus(hdq_data);
mutex_unlock(&hdq_data->hdq_mutex);
rtn:
return ret;
}
-/* Enable clocks and set the controller to HDQ/1W mode */
-static int omap_hdq_get(struct hdq_data *hdq_data)
-{
- int ret = 0;
-
- ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
- if (ret < 0) {
- ret = -EINTR;
- goto rtn;
- }
-
- if (OMAP_HDQ_MAX_USER == hdq_data->hdq_usecount) {
- dev_dbg(hdq_data->dev, "attempt to exceed the max use count");
- ret = -EINVAL;
- goto out;
- } else {
- hdq_data->hdq_usecount++;
- try_module_get(THIS_MODULE);
- if (1 == hdq_data->hdq_usecount) {
-
- pm_runtime_get_sync(hdq_data->dev);
-
- /* make sure HDQ/1W is out of reset */
- if (!(hdq_reg_in(hdq_data, OMAP_HDQ_SYSSTATUS) &
- OMAP_HDQ_SYSSTATUS_RESETDONE)) {
- ret = _omap_hdq_reset(hdq_data);
- if (ret)
- /* back up the count */
- hdq_data->hdq_usecount--;
- } else {
- /* select HDQ/1W mode & enable clocks */
- hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS,
- OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
- OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK |
- hdq_data->mode);
- hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG,
- OMAP_HDQ_SYSCONFIG_NOIDLE);
- hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
- }
- }
- }
-
-out:
- mutex_unlock(&hdq_data->hdq_mutex);
-rtn:
- return ret;
-}
-
-/* Disable clocks to the module */
-static int omap_hdq_put(struct hdq_data *hdq_data)
-{
- int ret = 0;
-
- ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
- if (ret < 0)
- return -EINTR;
-
- hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG,
- OMAP_HDQ_SYSCONFIG_AUTOIDLE);
- if (0 == hdq_data->hdq_usecount) {
- dev_dbg(hdq_data->dev, "attempt to decrement use count"
- " when it is zero");
- ret = -EINVAL;
- } else {
- hdq_data->hdq_usecount--;
- module_put(THIS_MODULE);
- if (0 == hdq_data->hdq_usecount)
- pm_runtime_put_sync(hdq_data->dev);
- }
- mutex_unlock(&hdq_data->hdq_mutex);
-
- return ret;
-}
-
/*
* W1 triplet callback function - used for searching ROM addresses.
* Registered only when controller is in 1-wire mode.
@@ -482,7 +347,12 @@ static u8 omap_w1_triplet(void *_hdq, u8 bdir)
OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK;
u8 mask = ctrl | OMAP_HDQ_CTRL_STATUS_DIR;
- omap_hdq_get(_hdq);
+ err = pm_runtime_get_sync(hdq_data->dev);
+ if (err < 0) {
+ pm_runtime_put_noidle(hdq_data->dev);
+
+ return err;
+ }
err = mutex_lock_interruptible(&hdq_data->hdq_mutex);
if (err < 0) {
@@ -490,7 +360,6 @@ static u8 omap_w1_triplet(void *_hdq, u8 bdir)
goto rtn;
}
- hdq_data->hdq_irqstatus = 0;
/* read id_bit */
hdq_reg_merge(_hdq, OMAP_HDQ_CTRL_STATUS,
ctrl | OMAP_HDQ_CTRL_STATUS_DIR, mask);
@@ -504,7 +373,9 @@ static u8 omap_w1_triplet(void *_hdq, u8 bdir)
}
id_bit = (hdq_reg_in(_hdq, OMAP_HDQ_RX_DATA) & 0x01);
- hdq_data->hdq_irqstatus = 0;
+ /* Must clear irqstatus for another RXCOMPLETE interrupt */
+ hdq_reset_irqstatus(hdq_data);
+
/* read comp_bit */
hdq_reg_merge(_hdq, OMAP_HDQ_CTRL_STATUS,
ctrl | OMAP_HDQ_CTRL_STATUS_DIR, mask);
@@ -547,18 +418,33 @@ static u8 omap_w1_triplet(void *_hdq, u8 bdir)
OMAP_HDQ_CTRL_STATUS_SINGLE);
out:
+ hdq_reset_irqstatus(hdq_data);
mutex_unlock(&hdq_data->hdq_mutex);
rtn:
- omap_hdq_put(_hdq);
+ pm_runtime_mark_last_busy(hdq_data->dev);
+ pm_runtime_put_autosuspend(hdq_data->dev);
+
return ret;
}
/* reset callback */
static u8 omap_w1_reset_bus(void *_hdq)
{
- omap_hdq_get(_hdq);
- omap_hdq_break(_hdq);
- omap_hdq_put(_hdq);
+ struct hdq_data *hdq_data = _hdq;
+ int err;
+
+ err = pm_runtime_get_sync(hdq_data->dev);
+ if (err < 0) {
+ pm_runtime_put_noidle(hdq_data->dev);
+
+ return err;
+ }
+
+ omap_hdq_break(hdq_data);
+
+ pm_runtime_mark_last_busy(hdq_data->dev);
+ pm_runtime_put_autosuspend(hdq_data->dev);
+
return 0;
}
@@ -569,37 +455,19 @@ static u8 omap_w1_read_byte(void *_hdq)
u8 val = 0;
int ret;
- /* First write to initialize the transfer */
- if (hdq_data->init_trans == 0)
- omap_hdq_get(hdq_data);
+ ret = pm_runtime_get_sync(hdq_data->dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(hdq_data->dev);
- ret = hdq_read_byte(hdq_data, &val);
- if (ret) {
- ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
- if (ret < 0) {
- dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
- return -EINTR;
- }
- hdq_data->init_trans = 0;
- mutex_unlock(&hdq_data->hdq_mutex);
- omap_hdq_put(hdq_data);
return -1;
}
- hdq_disable_interrupt(hdq_data, OMAP_HDQ_CTRL_STATUS,
- ~OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK);
+ ret = hdq_read_byte(hdq_data, &val);
+ if (ret)
+ ret = -1;
- /* Write followed by a read, release the module */
- if (hdq_data->init_trans) {
- ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
- if (ret < 0) {
- dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
- return -EINTR;
- }
- hdq_data->init_trans = 0;
- mutex_unlock(&hdq_data->hdq_mutex);
- omap_hdq_put(hdq_data);
- }
+ pm_runtime_mark_last_busy(hdq_data->dev);
+ pm_runtime_put_autosuspend(hdq_data->dev);
return val;
}
@@ -611,9 +479,12 @@ static void omap_w1_write_byte(void *_hdq, u8 byte)
int ret;
u8 status;
- /* First write to initialize the transfer */
- if (hdq_data->init_trans == 0)
- omap_hdq_get(hdq_data);
+ ret = pm_runtime_get_sync(hdq_data->dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(hdq_data->dev);
+
+ return;
+ }
/*
* We need to reset the slave before
@@ -623,31 +494,15 @@ static void omap_w1_write_byte(void *_hdq, u8 byte)
if (byte == W1_SKIP_ROM)
omap_hdq_break(hdq_data);
- ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
- if (ret < 0) {
- dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
- return;
- }
- hdq_data->init_trans++;
- mutex_unlock(&hdq_data->hdq_mutex);
-
ret = hdq_write_byte(hdq_data, byte, &status);
if (ret < 0) {
dev_dbg(hdq_data->dev, "TX failure:Ctrl status %x\n", status);
- return;
+ goto out_err;
}
- /* Second write, data transferred. Release the module */
- if (hdq_data->init_trans > 1) {
- omap_hdq_put(hdq_data);
- ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
- if (ret < 0) {
- dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
- return;
- }
- hdq_data->init_trans = 0;
- mutex_unlock(&hdq_data->hdq_mutex);
- }
+out_err:
+ pm_runtime_mark_last_busy(hdq_data->dev);
+ pm_runtime_put_autosuspend(hdq_data->dev);
}
static struct w1_bus_master omap_w1_master = {
@@ -656,6 +511,35 @@ static struct w1_bus_master omap_w1_master = {
.reset_bus = omap_w1_reset_bus,
};
+static int __maybe_unused omap_hdq_runtime_suspend(struct device *dev)
+{
+ struct hdq_data *hdq_data = dev_get_drvdata(dev);
+
+ hdq_reg_out(hdq_data, 0, hdq_data->mode);
+ hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
+
+ return 0;
+}
+
+static int __maybe_unused omap_hdq_runtime_resume(struct device *dev)
+{
+ struct hdq_data *hdq_data = dev_get_drvdata(dev);
+
+ /* select HDQ/1W mode & enable clocks */
+ hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS,
+ OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
+ OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK |
+ hdq_data->mode);
+ hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
+
+ return 0;
+}
+
+static const struct dev_pm_ops omap_hdq_pm_ops = {
+ SET_RUNTIME_PM_OPS(omap_hdq_runtime_suspend,
+ omap_hdq_runtime_resume, NULL)
+};
+
static int omap_hdq_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -677,23 +561,27 @@ static int omap_hdq_probe(struct platform_device *pdev)
if (IS_ERR(hdq_data->hdq_base))
return PTR_ERR(hdq_data->hdq_base);
- hdq_data->hdq_usecount = 0;
- hdq_data->rrw = 0;
mutex_init(&hdq_data->hdq_mutex);
+ ret = of_property_read_string(pdev->dev.of_node, "ti,mode", &mode);
+ if (ret < 0 || !strcmp(mode, "hdq")) {
+ hdq_data->mode = 0;
+ omap_w1_master.search = omap_w1_search_bus;
+ } else {
+ hdq_data->mode = 1;
+ omap_w1_master.triplet = omap_w1_triplet;
+ }
+
pm_runtime_enable(&pdev->dev);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 300);
ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0) {
+ pm_runtime_put_noidle(&pdev->dev);
dev_dbg(&pdev->dev, "pm_runtime_get_sync failed\n");
goto err_w1;
}
- ret = _omap_hdq_reset(hdq_data);
- if (ret) {
- dev_dbg(&pdev->dev, "reset failed\n");
- goto err_irq;
- }
-
rev = hdq_reg_in(hdq_data, OMAP_HDQ_REVISION);
dev_info(&pdev->dev, "OMAP HDQ Hardware Rev %c.%c. Driver in %s mode\n",
(rev >> 4) + '0', (rev & 0x0f) + '0', "Interrupt");
@@ -715,16 +603,8 @@ static int omap_hdq_probe(struct platform_device *pdev)
omap_hdq_break(hdq_data);
- pm_runtime_put_sync(&pdev->dev);
-
- ret = of_property_read_string(pdev->dev.of_node, "ti,mode", &mode);
- if (ret < 0 || !strcmp(mode, "hdq")) {
- hdq_data->mode = 0;
- omap_w1_master.search = omap_w1_search_bus;
- } else {
- hdq_data->mode = 1;
- omap_w1_master.triplet = omap_w1_triplet;
- }
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
omap_w1_master.data = hdq_data;
@@ -739,6 +619,7 @@ static int omap_hdq_probe(struct platform_device *pdev)
err_irq:
pm_runtime_put_sync(&pdev->dev);
err_w1:
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return ret;
@@ -746,23 +627,19 @@ err_w1:
static int omap_hdq_remove(struct platform_device *pdev)
{
- struct hdq_data *hdq_data = platform_get_drvdata(pdev);
+ int active;
- mutex_lock(&hdq_data->hdq_mutex);
-
- if (hdq_data->hdq_usecount) {
- dev_dbg(&pdev->dev, "removed when use count is not zero\n");
- mutex_unlock(&hdq_data->hdq_mutex);
- return -EBUSY;
- }
+ active = pm_runtime_get_sync(&pdev->dev);
+ if (active < 0)
+ pm_runtime_put_noidle(&pdev->dev);
- mutex_unlock(&hdq_data->hdq_mutex);
+ w1_remove_master_device(&omap_w1_master);
- /* remove module dependency */
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+ if (active >= 0)
+ pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- w1_remove_master_device(&omap_w1_master);
-
return 0;
}
@@ -779,6 +656,7 @@ static struct platform_driver omap_hdq_driver = {
.driver = {
.name = "omap_hdq",
.of_match_table = omap_hdq_dt_ids,
+ .pm = &omap_hdq_pm_ops,
},
};
module_platform_driver(omap_hdq_driver);
diff --git a/include/dt-bindings/interconnect/qcom,msm8916.h b/include/dt-bindings/interconnect/qcom,msm8916.h
new file mode 100644
index 000000000000..359a75feb198
--- /dev/null
+++ b/include/dt-bindings/interconnect/qcom,msm8916.h
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Qualcomm interconnect IDs
+ *
+ * Copyright (c) 2019, Linaro Ltd.
+ * Author: Georgi Djakov <georgi.djakov@linaro.org>
+ */
+
+#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_MSM8916_H
+#define __DT_BINDINGS_INTERCONNECT_QCOM_MSM8916_H
+
+#define BIMC_SNOC_SLV 0
+#define MASTER_JPEG 1
+#define MASTER_MDP_PORT0 2
+#define MASTER_QDSS_BAM 3
+#define MASTER_QDSS_ETR 4
+#define MASTER_SNOC_CFG 5
+#define MASTER_VFE 6
+#define MASTER_VIDEO_P0 7
+#define SNOC_MM_INT_0 8
+#define SNOC_MM_INT_1 9
+#define SNOC_MM_INT_2 10
+#define SNOC_MM_INT_BIMC 11
+#define PCNOC_SNOC_SLV 12
+#define SLAVE_APSS 13
+#define SLAVE_CATS_128 14
+#define SLAVE_OCMEM_64 15
+#define SLAVE_IMEM 16
+#define SLAVE_QDSS_STM 17
+#define SLAVE_SRVC_SNOC 18
+#define SNOC_BIMC_0_MAS 19
+#define SNOC_BIMC_1_MAS 20
+#define SNOC_INT_0 21
+#define SNOC_INT_1 22
+#define SNOC_INT_BIMC 23
+#define SNOC_PCNOC_MAS 24
+#define SNOC_QDSS_INT 25
+
+#define BIMC_SNOC_MAS 0
+#define MASTER_AMPSS_M0 1
+#define MASTER_GRAPHICS_3D 2
+#define MASTER_TCU0 3
+#define MASTER_TCU1 4
+#define SLAVE_AMPSS_L2 5
+#define SLAVE_EBI_CH0 6
+#define SNOC_BIMC_0_SLV 7
+#define SNOC_BIMC_1_SLV 8
+
+#define MASTER_BLSP_1 0
+#define MASTER_DEHR 1
+#define MASTER_LPASS 2
+#define MASTER_CRYPTO_CORE0 3
+#define MASTER_SDCC_1 4
+#define MASTER_SDCC_2 5
+#define MASTER_SPDM 6
+#define MASTER_USB_HS 7
+#define PCNOC_INT_0 8
+#define PCNOC_INT_1 9
+#define PCNOC_MAS_0 10
+#define PCNOC_MAS_1 11
+#define PCNOC_SLV_0 12
+#define PCNOC_SLV_1 13
+#define PCNOC_SLV_2 14
+#define PCNOC_SLV_3 15
+#define PCNOC_SLV_4 16
+#define PCNOC_SLV_8 17
+#define PCNOC_SLV_9 18
+#define PCNOC_SNOC_MAS 19
+#define SLAVE_BIMC_CFG 20
+#define SLAVE_BLSP_1 21
+#define SLAVE_BOOT_ROM 22
+#define SLAVE_CAMERA_CFG 23
+#define SLAVE_CLK_CTL 24
+#define SLAVE_CRYPTO_0_CFG 25
+#define SLAVE_DEHR_CFG 26
+#define SLAVE_DISPLAY_CFG 27
+#define SLAVE_GRAPHICS_3D_CFG 28
+#define SLAVE_IMEM_CFG 29
+#define SLAVE_LPASS 30
+#define SLAVE_MPM 31
+#define SLAVE_MSG_RAM 32
+#define SLAVE_MSS 33
+#define SLAVE_PDM 34
+#define SLAVE_PMIC_ARB 35
+#define SLAVE_PCNOC_CFG 36
+#define SLAVE_PRNG 37
+#define SLAVE_QDSS_CFG 38
+#define SLAVE_RBCPR_CFG 39
+#define SLAVE_SDCC_1 40
+#define SLAVE_SDCC_2 41
+#define SLAVE_SECURITY 42
+#define SLAVE_SNOC_CFG 43
+#define SLAVE_SPDM 44
+#define SLAVE_TCSR 45
+#define SLAVE_TLMM 46
+#define SLAVE_USB_HS 47
+#define SLAVE_VENUS_CFG 48
+#define SNOC_PCNOC_SLV 49
+
+#endif
diff --git a/include/linux/alcor_pci.h b/include/linux/alcor_pci.h
index 4416df597526..8274ed525e9f 100644
--- a/include/linux/alcor_pci.h
+++ b/include/linux/alcor_pci.h
@@ -17,6 +17,7 @@
#define PCI_ID_ALCOR_MICRO 0x1AEA
#define PCI_ID_AU6601 0x6601
#define PCI_ID_AU6621 0x6621
+#define PCI_ID_AU6625 0x6625
#define MHZ_TO_HZ(freq) ((freq) * 1000 * 1000)
diff --git a/include/linux/extcon.h b/include/linux/extcon.h
index 2bdf643d8593..1b1d77ec2114 100644
--- a/include/linux/extcon.h
+++ b/include/linux/extcon.h
@@ -170,7 +170,7 @@ struct extcon_dev;
* Following APIs get the connected state of each external connector.
* The 'id' argument indicates the defined external connector.
*/
-extern int extcon_get_state(struct extcon_dev *edev, unsigned int id);
+int extcon_get_state(struct extcon_dev *edev, unsigned int id);
/*
* Following APIs get the property of each external connector.
@@ -181,10 +181,10 @@ extern int extcon_get_state(struct extcon_dev *edev, unsigned int id);
* for each external connector. They are used to get the capability of the
* property of each external connector based on the id and property.
*/
-extern int extcon_get_property(struct extcon_dev *edev, unsigned int id,
+int extcon_get_property(struct extcon_dev *edev, unsigned int id,
unsigned int prop,
union extcon_property_value *prop_val);
-extern int extcon_get_property_capability(struct extcon_dev *edev,
+int extcon_get_property_capability(struct extcon_dev *edev,
unsigned int id, unsigned int prop);
/*
@@ -196,38 +196,38 @@ extern int extcon_get_property_capability(struct extcon_dev *edev,
* extcon_register_notifier_all(*edev, *nb) : Register a notifier block
* for all supported external connectors of the extcon.
*/
-extern int extcon_register_notifier(struct extcon_dev *edev, unsigned int id,
+int extcon_register_notifier(struct extcon_dev *edev, unsigned int id,
struct notifier_block *nb);
-extern int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id,
+int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id,
struct notifier_block *nb);
-extern int devm_extcon_register_notifier(struct device *dev,
+int devm_extcon_register_notifier(struct device *dev,
struct extcon_dev *edev, unsigned int id,
struct notifier_block *nb);
-extern void devm_extcon_unregister_notifier(struct device *dev,
+void devm_extcon_unregister_notifier(struct device *dev,
struct extcon_dev *edev, unsigned int id,
struct notifier_block *nb);
-extern int extcon_register_notifier_all(struct extcon_dev *edev,
+int extcon_register_notifier_all(struct extcon_dev *edev,
struct notifier_block *nb);
-extern int extcon_unregister_notifier_all(struct extcon_dev *edev,
+int extcon_unregister_notifier_all(struct extcon_dev *edev,
struct notifier_block *nb);
-extern int devm_extcon_register_notifier_all(struct device *dev,
+int devm_extcon_register_notifier_all(struct device *dev,
struct extcon_dev *edev,
struct notifier_block *nb);
-extern void devm_extcon_unregister_notifier_all(struct device *dev,
+void devm_extcon_unregister_notifier_all(struct device *dev,
struct extcon_dev *edev,
struct notifier_block *nb);
/*
* Following APIs get the extcon_dev from devicetree or by through extcon name.
*/
-extern struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name);
-extern struct extcon_dev *extcon_find_edev_by_node(struct device_node *node);
-extern struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev,
+struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name);
+struct extcon_dev *extcon_find_edev_by_node(struct device_node *node);
+struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev,
int index);
/* Following API get the name of extcon device. */
-extern const char *extcon_get_edev_name(struct extcon_dev *edev);
+const char *extcon_get_edev_name(struct extcon_dev *edev);
#else /* CONFIG_EXTCON */
static inline int extcon_get_state(struct extcon_dev *edev, unsigned int id)
diff --git a/include/linux/interconnect-provider.h b/include/linux/interconnect-provider.h
index b16f9effa555..0c494534b4d3 100644
--- a/include/linux/interconnect-provider.h
+++ b/include/linux/interconnect-provider.h
@@ -92,17 +92,26 @@ struct icc_node {
#if IS_ENABLED(CONFIG_INTERCONNECT)
+int icc_std_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
+ u32 peak_bw, u32 *agg_avg, u32 *agg_peak);
struct icc_node *icc_node_create(int id);
void icc_node_destroy(int id);
int icc_link_create(struct icc_node *node, const int dst_id);
int icc_link_destroy(struct icc_node *src, struct icc_node *dst);
void icc_node_add(struct icc_node *node, struct icc_provider *provider);
void icc_node_del(struct icc_node *node);
+int icc_nodes_remove(struct icc_provider *provider);
int icc_provider_add(struct icc_provider *provider);
int icc_provider_del(struct icc_provider *provider);
#else
+static inline int icc_std_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
+ u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
+{
+ return -ENOTSUPP;
+}
+
static inline struct icc_node *icc_node_create(int id)
{
return ERR_PTR(-ENOTSUPP);
@@ -130,6 +139,11 @@ void icc_node_del(struct icc_node *node)
{
}
+static inline int icc_nodes_remove(struct icc_provider *provider)
+{
+ return -ENOTSUPP;
+}
+
static inline int icc_provider_add(struct icc_provider *provider)
{
return -ENOTSUPP;
diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index b7c9eca4332a..b451bb622335 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -546,7 +546,8 @@ struct sdw_slave_ops {
* @debugfs: Slave debugfs
* @node: node for bus list
* @port_ready: Port ready completion flag for each Slave port
- * @dev_num: Device Number assigned by Bus
+ * @dev_num: Current Device Number, values can be 0 or dev_num_sticky
+ * @dev_num_sticky: one-time static Device Number assigned by Bus
* @probed: boolean tracking driver state
* @probe_complete: completion utility to control potential races
* on startup between driver probe/initialization and SoundWire
@@ -575,6 +576,7 @@ struct sdw_slave {
struct list_head node;
struct completion *port_ready;
u16 dev_num;
+ u16 dev_num_sticky;
bool probed;
struct completion probe_complete;
struct completion enumeration_complete;
diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h
index 93b83bdf8035..979b41b5dcb4 100644
--- a/include/linux/soundwire/sdw_intel.h
+++ b/include/linux/soundwire/sdw_intel.h
@@ -5,6 +5,7 @@
#define __SDW_INTEL_H
#include <linux/irqreturn.h>
+#include <linux/soundwire/sdw.h>
/**
* struct sdw_intel_stream_params_data: configuration passed during
@@ -93,6 +94,11 @@ struct sdw_intel_link_res;
*/
#define SDW_INTEL_CLK_STOP_BUS_RESET BIT(3)
+struct sdw_intel_slave_id {
+ int link_id;
+ struct sdw_slave_id id;
+};
+
/**
* struct sdw_intel_ctx - context allocated by the controller
* driver probe
@@ -101,9 +107,12 @@ struct sdw_intel_link_res;
* hardware capabilities after all power dependencies are settled.
* @link_mask: bit-wise mask listing SoundWire links reported by the
* Controller
+ * @num_slaves: total number of devices exposed across all enabled links
* @handle: ACPI parent handle
* @links: information for each link (controller-specific and kept
* opaque here)
+ * @ids: array of slave_id, representing Slaves exposed across all enabled
+ * links
* @link_list: list to handle interrupts across all links
* @shim_lock: mutex to handle concurrent rmw access to shared SHIM registers.
*/
@@ -111,8 +120,10 @@ struct sdw_intel_ctx {
int count;
void __iomem *mmio_base;
u32 link_mask;
+ int num_slaves;
acpi_handle handle;
struct sdw_intel_link_res *links;
+ struct sdw_intel_slave_id *ids;
struct list_head link_list;
struct mutex shim_lock; /* lock for access to shared SHIM registers */
};
diff --git a/include/uapi/misc/pvpanic.h b/include/uapi/misc/pvpanic.h
new file mode 100644
index 000000000000..54b7485390d3
--- /dev/null
+++ b/include/uapi/misc/pvpanic.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+
+#ifndef __PVPANIC_H__
+#define __PVPANIC_H__
+
+#define PVPANIC_PANICKED (1 << 0)
+#define PVPANIC_CRASH_LOADED (1 << 1)
+
+#endif /* __PVPANIC_H__ */