Merge "jtagmm: Modify save-restore driver to use reg-names property"
diff --git a/Documentation/ABI/testing/sysfs-bus-msm_subsys b/Documentation/ABI/testing/sysfs-bus-msm_subsys
index fcfb1d4..f915a46 100644
--- a/Documentation/ABI/testing/sysfs-bus-msm_subsys
+++ b/Documentation/ABI/testing/sysfs-bus-msm_subsys
@@ -16,3 +16,16 @@
This file supports poll(3) to detect when a subsystem changes
state. Use POLLPRI to detect state changes.
+
+What: /sys/bus/msm_subsys/devices/.../restart_level
+Date: December 2012
+Contact: Stephen Boyd <sboyd@codeaurora.org>
+Description:
+ Shows the restart level of a subsystem. The level is taken into
+ account when the subsystem is restarted via
+ subsystem_restart{_dev}(). Current supported states are:
+
+ SYSTEM - reset the entire system
+ RELATED - reset this subsystem and the other subsystems
+ related to this one. Having no other
+ subsystems related to this subsystem is valid.
diff --git a/Documentation/arm/msm/n_smux.txt b/Documentation/arm/msm/n_smux.txt
new file mode 100644
index 0000000..c9123ad
--- /dev/null
+++ b/Documentation/arm/msm/n_smux.txt
@@ -0,0 +1,630 @@
+Introduction
+============
+
+The Serial Mux (SMUX) is a TTY Line Discipline that multiplexes
+multiple logical channels onto a single TTY serial channel. The
+logical channels are exposed through a kernel API.
+
+Companion adaptation drivers use the kernel API to expose logical
+channels as character devices (SMUX CTL - smux_ctl.c) to the user-space
+and as net devices (SMUX RMNET - msm_rmnet_smux.c) to the TCP/IP stack.
+
+Power control calls are supported to the physical serial driver to
+optimize power usage.
+
+
+Software description
+====================
+
+The Serial Mux driver will be similar in design to the SDIO DMUX and
+BAM DMUX drivers and will use the same multiplexing protocol with
+additional commands to support inactivity timeouts along with
+power-down and wake-up handshaking. Companion adaptation drivers will
+support data-plane traffic through TCP/IP (SMUX_RMNET) and control
+plane traffic through SMUX_CTL.
+
+
+ ttyHS0 RMNET[0..N] smuxctl[0..M]
+ | | |
+ | | |
+ | ------------------ -------------------
+ | | IP Framework | | VFS Framework |
+ | ------------------ -------------------
+ | | | | |
+ | | | | |
+ | ------- ------- ------- -------
+ | | Rmnet | | Rmnet | | CDEV | | CDEV |
+ | | Dev 0 |...| Dev N | | Dev 0 |...| Dev M |
+ | --------------------- --------------------- -------------
+ | | | | | | Other |
+ | | msm_rmnet_smux | | smux_ctl | | Kernel-only |
+ | | | | | | Clients |
+ | --------------------- --------------------- -------------
+ | | | | | |
+ | | | | | |
+ | | | | | |
+ | | | | | |
+ | ---------------------------------------------------
+ | |
+ | |
+ | |
+ | |
+ --------------- --------------------
+ | | | |
+ | TTY Framework | <- Line Discipline -> | SMUX |
+ | | | |
+ --------------- --------------------
+ | |
+ | |
+ --------------- |
+ | | |
+ | HS UART |<---------- Power API -----------
+ | |
+ ---------------
+ |
+ V
+ To Remote System
+
+
+Each logical channel will contain package management structures
+including a watermark to ensure fair usage of the physical layer by
+competing logical channels. All data for logical channels will be
+processed in FIFO order.
+
+Once data has been queued with SMUX, processing, copying of data, and
+notification to clients will be done using a combination of the TTY
+framework notification context and a workqueue. The lifetime of all
+buffers is controlled by the clients with SMUX taking temporary
+ownership of the buffers for read and write operations.
+
+The physical transport is assumed to be perfect and all errors will be
+handled by notifying the client of the failure. Watermark support and
+round-robin scheduling ensure that individual logical channels do not
+starve other logical channels.
+
+Data stalls caused by failure of the remote system are handled by
+Subsystem Restart. The restart logic will notify clients of the
+failure and all read and write buffers will be returned to the client
+with an error notification.
+
+Design
+======
+
+The goals for SMUX are to:
+ 1) multiplex multiple logical channels into a single physical
+ channel
+ 2) support a kernel API
+ 3) provide power control of the physical layer
+
+In addition, the companion adapter modules have the goals:
+ 1) support userspace character-device clients (smux_ctl)
+ 2) support net devices through the TCP/IP stack (msm_rmnet_smux)
+
+Alternate designs consider including 3GPP 27.010 MUX protocol
+implementations and existing SDIO CMUX/DMUX implementations.
+
+The 3GPP 27.010 MUX protocol as implemented in both n_gsm.c and OpenEZX
+looked promising at first glance. However, upon further inspection,
+the implementations did not fully implement the power-control portions
+of the 27.010 MUX protocol. They also did not support kernel clients
+as they were designed to work only with userspace through TTY devices.
+The code was reviewed to determine the effort to add power-control
+signaling to the physical transport driver and to add a kernel API, but
+it was deemed that adding the API to support both of these behaviors
+would be difficult to do in a generic way such that it would be
+accepted by the upstream community.
+
+The SDIO CMUX/DMUX drivers do not have power control in them and the
+CMUX and DMUX drivers both require a separate physical channel. To use
+them, we would need to create an additional mux layer that would sit
+between CMUX/DMUX and the HS UART driver which would add another MUX
+header.
+
+Design - MUX Protocol
+=====================
+The MUX packet consists of a header (detailed below) and a payload.
+All values are in little-endian format and all reserved fields are set
+to zero unless otherwise mentioned in the individual command
+descriptions.
+
+Invalid commands and malformed commands will be logged to the kernel log
+as an error and ignored.
+
+ -----------------------------------------
+ |31 24| 16| 8| 0|
+ |----------|---------|----------|---------|
+ | Magic Number | Flags | CMD |
+ |----------|---------|----------|---------|
+ | Pad Len | LCID | Packet Length (N) |
+ |-----------------------------------------|
+ | Data Payload (0..N bytes) |
+ |-----------------------------------------|
+ | Pad Data (0..Pad Len bytes) |
+ -----------------------------------------
+
+Field definitions:
+ * Magic Number - always 0x33FC
+ * Flags - flags for individual commands
+ * CMD - SMUX command
+ * Pad Len - Padding in bytes at the end of the payload
+ * LCID - Logical channel ID
+ * Packet Length - Length of the data payload in bytes
+
+Commands
+ 0x0 - Data
+ 0x1 - Open Logical Channel
+ 0x2 - Close Logical Channel
+ 0x3 - Status
+ 0x4 - Power Control
+
+Data Command
+------------
+The Data command sends data on an already fully-opened logical channel.
+
+Flags:
+ * Bits 0:7 - Reserved
+
+Open Logical Channel Command
+----------------------------
+The Open command is a request to open a logical channel. Each channel
+will have a local and remote open flag. The remote open flag will be
+set to open when receiving an open command and responding with an open
+ACK. The local open flag is set to open when sending an open command
+and receiving an ACK.
+
+ Remote Side | Local Side
+ |
+ SMUX Client SMUX SMUX SMUX Client
+ | | | |
+ | Open | | |
+ |--------->| | |
+ | | Open Logical Channel | |
+ | |---------------------->| |
+ | | |--- |
+ | | | | Set Remote Open |
+ | | |<-- |
+ | | Open ACK | |
+ | |<----------------------| |
+ | |--- | |
+ | | | Set Local Open | |
+ | |<-- | |
+ | ... ... ...
+ | | | msm_smux_open() |
+ | | |<-----------------------|
+ | | Open Logical Channel | |
+ | |<----------------------| |
+ | | | |
+ | |--- | |
+ | | | Set Remote Open | |
+ | |<-- | |
+ | | Open ACK | |
+ | |---------------------->| |
+ | | |--- |
+ | | | | Set Local Open |
+ | | |<-- |
+ | | | notify(SMUX_CONNECTED) |
+ | | |----------------------->|
+
+
+ Logical channel is now fully open and can receive
+ and transmit data.
+
+No data shall be transmitted over the physical link for the logical
+channel unless the channel is open.
+
+Flags:
+ * Bit 0 - 1 = ACK
+ * Bit 1 - Power Collapse Enable
+ * Bit 2 - Remote Loopback Enable
+ * Bits 3:7 - Reserved
+
+Power Collapse Enable (bit 1) enables power-collapse handshaking when
+processing an open command. The first logical channel open command
+received from the remote side will set the global power control state
+and all subsequent open commands should use the same value of the Power
+Collapse bit. The value of this bit can be changed during runtime by
+closing all logical channels and then re-opening them with the new
+global state.
+
+If the protocol stack does not support power collapse and it receives
+an open command with the Power Collapse Enable bit set, then it
+shall respond with an open command with the Power Collapse Enable bit
+cleared.
+
+If Power Collapse is disabled, then Power Control Commands should not
+be sent.
+
+Remote Loopback Enable (bit 2) enables loopback support when data is
+received from the remote side. In this case, SMUX should echo the
+received data packet back to the sender.
+
+Close Logical Channel Command
+-----------------------------
+The Close command closes the logical channel and updates the internal
+open state flags. The remote open flag will be set to closed when
+receiving a close command and responding with an close ACK. The local
+open flag is set to closed when sending a close command and receiving an
+ACK.
+
+No data shall be transmitted over the physical link for the logical
+channel after receiving a close command and responding with the close
+ACK.
+
+Flags:
+ * Bit 0 - ACK (when set to 1)
+ * Bits 1:7 - Reserved
+
+
+Status Command
+--------------
+The Status Command updates the channel status signals which include four
+ITU v.24 status bits in the lower nibble of the flags field along with a
+logical channel flow-control signal. The v.24 signals are pass-through
+and do not affect the state of SMUX.
+
+The Logical Channel Flow Control bit will disable TX on the logical
+channel when set and send a flow-control notification to the logical
+channel client. Any further attempts to transmit will result in an
+error return code.
+
+Flags:
+ * Bit 0 - RTC (DTR/DSR)
+ * Bit 1 - RTR (RTS/CTS)
+ * Bit 2 - RI
+ * Bit 3 - DCD
+ * Bit 4 - Logical Channel Flow Control
+ * Bits 5:7 - Reserved
+
+
+Power Control Command
+---------------------
+The physical layer requires a variable amount of time to wakeup from
+power collapse, reconfigure the hardware, and start processing data.
+Data may be lost until the wakeup has been completed. Because of this,
+a character-based wakeup method will be used to ensure that the remote
+side is active and ready before sending SMUX commands.
+
+If the remote side has previously requested power-down (boot-up state),
+then a wakeup request character is sent at periodic intervals (1 ms or
+8 character-widths, whichever is larger) until a wakeup-acknowledge character
+has been received. Normal transmit operations can then be performed. Once an
+activity timeout occurs, then a sleep vote should be sent to the remote side to
+let it know that the channel is no longer needed. The remote side should
+respond with an ACK.
+
+The following state diagram shows the full sequence of power state transitions.
+This state machine is identical on both the local and remote sides. The states
+marked "(internal)" are transitional states used in this driver that are not
+part of the power states tracked by the remote side. The edges are labeled
+using the format CONDITION:ACTION where condition is the guard condition that
+must be true for the edge to be taken and ACTION is the action that will be
+taken.
+
+ +--------------+ RX Sleep ACK || RX Sleep Request
+ :Flush and power-down | Powering |<---------+
+ UART +---------+ Down Flush | |
+ | | (internal) | |
+ | +--------------+ |
+ | ^ |
+ | | +-------+------+
+ v | | | |
+ +--------------+ | | Powering |
+ | | | | Down |<-----+
+Init --->| OFF | | | | |
+ | |------+ | +--------------+ |
+ | | | | |
+ +------+-------+ | | TX Sleep Request
+ | | | Complete
+ | | | |
+ Data ready to send | | |
+ :TX Wakeup Request | |RX Sleep Request |
+ | | |:TX Sleep ACK |
+ | | +------------+ +-------+------+
+ | | | | Turning Off^|
+ | | | | Flush |
+ | | | | (internal) |
+ | |RX Wakeup Request | +--------------+
+ | |:TX Wakeup ACK | ^
+ | | | |
+ | | | Inactivity Timeout
+ | +--------------+ | :TX Sleep Request
+ | | | |
+ v v | |
+ +--------------+ RX Wakeup ACK +-------+------+ |
+ | +------------------>| UP |+-----+
+ | Powering | | |
+ | Up +------------------>| Packet TX/RX |
+ +----->| | RX Wakeup Request | is now active|<------+
+ | +--+-----------+ :TX Wakeup ACK +----------+---+ |
+ | | | |
+ +---------+ +-----------+
+ Wakeup Request Timeout RX Wakeup Request
+ :TX Wakeup Request :TX Wakeup ACK
+
+
+In-band wakeup bytes:
+ * 0xfd - Wakeup Request
+ * 0xfe - Wakeup Acknowledge
+
+Flags:
+ * Bit 0 - ACK (when set to 1)
+ * Bit 1 - 1 = Sleep Request
+ * Bits 2:7 - Reserved
+
+Initial SMUX State
+------------------
+The boot-up state of SMUX is in power-disabled mode and all logical
+channels closed. Before sending any commands to open logical channels,
+the remote SMUX must be woken up.
+
+Power Management
+================
+
+Power management will consist of wakeup and shutdown control of the
+physical layer based upon an activity timeout. Wakelocks will be
+utilized to prevent the system from going to sleep while the transport
+is active. The activity timeout is anticipated to be 500 ms, but this
+is subject to tuning to meet power and performance specifications.
+
+SMP/multi-core
+==============
+
+Locking and synchronization will be done using mutexes or spinlocks
+where appropriate. The software will be structured such that locking
+can be kept to a minimum by only locking when items are added and
+removed from lists.
+
+Security
+========
+
+No new security issues are anticipated as communication with userspace
+is done through the existing TCP/IP and CDEV frameworks.
+
+Performance
+===========
+
+The throughput requirements for this design are on the order of 250Kbps
+so throughput concerns are not expected to be an issue. However, in
+the hope that this driver can be leveraged in the future instead of
+writing yet another multiplexing layer, performance will be considered
+when making design decisions.
+
+Interface
+=========
+
+The kernel API consists of commands to read and write data, vote for
+power, and verify the state of the logical channels.
+
+
+Open
+----
+int msm_smux_open(uint32_t lcid, void *priv,
+ void (*notify)(void *priv, int event_type, void *metadata),
+ int (*get_rx_buffer)(void *priv, void **pkt_priv,
+ void **buffer, int size))
+
+Open a logical channel. The channel will be first opened locally and
+an open command will be sent to the remote processor. Once the remote
+processor sends an open command, then the port will be fully open and
+ready for data operations -- the client will be notified with an
+SMUX_CONNECTED notification.
+
+For receive notifications, the driver will read the SMUX header into
+temporary storage and then when the logical channel and size are both
+known, the driver will call the get_rx_buffer() function to request a
+buffer for the data. The client should return 0 upon success or < 0
+using standard Linux error codes if an error occurred. If the error
+code is EAGAIN, then the call to get_rx_buffer() will be retried once,
+otherwise the data will be discarded by the driver and a kernel error
+message logged.
+
+Once the receive data has been processed, the notify() function will be
+called with metadata pointing to an instance of struct smux_meta_read
+and the event type will either be SMUX_READ_DONE for successful cases or
+SMUX_READ_FAIL for failure cases.
+
+/*
+ * Notification events that are passed to the notify() function.
+ *
+ * If the @metadata argument in the notifier is non-null, then it will
+ * point to the associated struct smux_meta_* structure.
+ */
+enum {
+ SMUX_CONNECTED, /* @metadata is null */
+ SMUX_DISCONNECTED,
+ SMUX_READ_DONE,
+ SMUX_READ_FAIL,
+ SMUX_WRITE_DONE,
+ SMUX_WRITE_FAIL,
+ SMUX_TIOCM_UPDATE,
+ SMUX_LOW_WM_HIT, /* @metadata is NULL */
+ SMUX_HIGH_WM_HIT, /* @metadata is NULL */
+};
+
+/*
+ * Metadata for SMUX_READ_DONE/SMUX_READ_FAIL notification
+ *
+ * @pkt_priv: Packet-specific private data
+ * @buffer: Buffer pointer passed into msm_smux_write
+ * @len: Buffer length passed into msm_smux_write
+ */
+struct smux_meta_read {
+ void *pkt_priv;
+ void *buffer;
+ int len;
+};
+
+Close
+-----
+int msm_smux_close(uint32_t lcid)
+
+Closes a logical channel locally and sends a close command to the
+remote host.
+
+If there is pending transmit or receive data, then SMUX_WRITE_FAIL and
+SMUX_READ_FAIL notifications will be made to return ownership of the
+buffers to the client.
+
+Once the remote side of the port has been closed, the notify function
+will be called with the event SMUX_DISCONNECTED and metadata pointing
+to a struct smux_meta_disconnected structure. After this point, no
+further notifications will be performed.
+
+/*
+ * Metadata for SMUX_DISCONNECTED notification
+ *
+ * @is_ssr: Disconnect caused by subsystem restart
+ */
+struct smux_meta_disconnected {
+ int is_ssr;
+};
+
+
+Write
+-----
+int msm_smux_write(uint32_t lcid, void *pkt_priv, void *data, int len)
+
+Queues data for transmit. Once the data has been transmitted, the
+SMUX_WRITE_DONE or SMUX_WRITE_FAIL notifications will be sent with
+metadata pointing to an instance of struct smux_meta_write.
+
+If the high watermark has been exceeded, then further writes will
+return -EAGAIN.
+
+Data may be written as soon as the local side of the port has been
+opened, but the data will not be transmitted until the channel has been
+fully opened and the SMUX_CONNECTED event has been sent.
+
+/*
+ * Metadata for SMUX_WRITE_DONE/SMUX_WRITE_FAIL notification
+ *
+ * @pkt_priv: Packet-specific private data
+ * @buffer: Buffer pointer returned by get_rx_buffer()
+ * @len: Buffer length returned by get_rx_buffer()
+ */
+struct smux_meta_write {
+ void *pkt_priv;
+ void *buffer;
+ int len;
+};
+
+Watermark
+---------
+ int msm_smux_is_ch_full(uint32_t lcid)
+ int msm_smux_is_ch_low(uint32_t lcid)
+
+A channel watermark is used to keep individual clients from using
+excessive internal resources. The client may call
+msm_smux_is_ch_full() after every msm_smux_write() operation and if the
+watermark is high, it should not queue any more packets for
+transmission. As an alternative, the client may base this decision
+upon receiving an SMUX_HIGH_WM_HIT notification.
+
+Likewise, the client may call msm_smux_is_ch_low() after every
+SMUX_WRITE_DONE or SMUX_WRITE_FAIL notification and if the watermark is
+low, then new transmit operations can be started. As an alternative,
+the client may base this decision upon receiving an SMUX_LOW_WM_HIT
+notification.
+
+Control Signals
+---------------
+ long msm_smux_tiocm_get(uint32_t lcid)
+ long msm_smux_tiocm_set(uint32_t lcid, uint32_t set, uint32_t clear)
+
+The TIOCM bits do not affect the SMUX internal state as they are
+pass-through for the clients. The client can receive notifications of
+state changes through the SMUX_TIOCM_UPDATE command.
+
+See the "Status Command" section for details on the TIOCM bits.
+
+/*
+ * Metadata for SMUX_TIOCM_UPDATE notification
+ *
+ * @previous: Previous TIOCM state
+ * @current: Current TIOCM state
+ *
+ */
+struct smux_meta_tiocm {
+ uint32_t previous;
+ uint32_t current;
+};
+
+Subsystem Restart
+-----------------
+Subsystem restart is handled by sending a disconnect notification
+followed by sending read and write fail notifications to each client.
+This returns ownership of the read and write buffers to the clients for
+client-appropriate handling.
+
+The sequence of notifications shall be:
+ 1) SMUX_DISCONNECTED notification with @metadata->is_ssr == 1
+ 2) SMUX_WRITE_FAIL for each packet in TX queue
+ 3) SMUX_READ_FAIL for any RX packet in progress
+
+After the completion of the sequence, the client should call msm_smux_close()
+followed by a call to msm_smux_open() to re-open the port.
+
+
+Debug / Testing
+---------------
+
+Several debugfs nodes will be exported under the n_gsm directory for
+testing and debugging.
+ * tbl - prints table of logical channels
+ * stats - prints transfer statistics
+ * enable_local_loopback - echo LCID to enable loopback
+ * disable_local_loopback - echo LCID to enable loopback
+ * enable_remote_loopback - echo LCID to enable loopback
+ * disable_remote_loopback - echo LCID to enable loopback
+
+Driver parameters
+=================
+
+A module parameter called debug_mask will be exported to allow a user
+to set the log level for debugging.
+
+Config options
+==============
+
+No configuration options are planned.
+
+Dependencies
+============
+
+The msm_rmnet_smux and smux_ctl drivers are part of this project and
+are used to interface with the Linux TCP/IP framework and user space.
+
+The physical transport is the HS UART driver which will be extended to
+add a kernel API (the current interface is a TTY interface).
+
+Initialization of dependency drivers is handled using the platform
+device framework. When SMUX is loaded as a line discipline of the TTY
+Framework, it will register separate device drivers with the following
+device names:
+ * SMUX_CTL
+ * SMUX_RMNET
+ * SMUX_DUN_DATA_HSUART
+ * SMUX_RMNET_DATA_HSUART
+ * SMUX_RMNET_CTL_HSUART
+ * SMUX_DIAG
+
+The drivers are removed when SMUX is unloaded from the line discipline.
+
+
+User space utilities
+====================
+
+No userspace utilities are planned aside from testing and example
+applications.
+
+Known issues
+============
+
+None.
+
+To do
+=====
+Once completed, benchmark to determine if FIFO packet scheduling is
+sufficient or if a different scheduling algorithm such as deficit
+round-robin or deficit FIFO scheduling is needed to fairly handle
+variable-sized packets.
diff --git a/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt b/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt
new file mode 100644
index 0000000..6ac80f1
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt
@@ -0,0 +1,29 @@
+* MSM Sleep status
+
+MSM Sleep status device is used to check the power collapsed status of a
+offlined core. The core that initiates the hotplug would wait on the
+sleep status device before CPU_DEAD notifications are sent out. Some hardware
+devices require that the offlined core is power collapsed before turning off
+the resources that are used by the offlined core.
+
+This device is dependent on the pm-8x60 device, which configures the low power
+mode of respective cores. The sleep status is only valid when the core enters
+a low power mode. The device is a child node to pm-8x60 node which is documented
+in Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
+
+The required properties of sleep status device are:
+
+- compatible: qcom,cpu-sleep-status
+- reg: physical address of the sleep status register for Core 0
+- qcom,cpu-alias-addr - On MSM chipset, the each cores registers are at a
+ fixed offset each other.
+- qcom,cpu-sleep-status-mask - The bit mask within the status register that
+ indicates the Core's sleep state.
+
+Example:
+ qcom,cpu-sleep-status@f9088008 {
+ compatible = "qcom,cpu-sleep-status";
+ reg = <0xf9088008 0x4>;
+ qcom,cpu-alias-addr = <0x10000>;
+ qcom,sleep-status-mask= <0x80000>;
+ };
diff --git a/Documentation/devicetree/bindings/power/qpnp-bms.txt b/Documentation/devicetree/bindings/power/qpnp-bms.txt
index 708ada1..5b22752 100644
--- a/Documentation/devicetree/bindings/power/qpnp-bms.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-bms.txt
@@ -40,13 +40,16 @@
The bms will not accept new ocvs between these
thresholds.
- qcom,low-soc-calculate-soc-threshold : The SoC threshold for when
- the period calculate_soc work speeds up. This ensures
+ the periodic calculate_soc work speeds up. This ensures
SoC is updated in userspace constantly when we are near
shutdown.
+- qcom,low-voltage-threshold : The battery voltage threshold in micro-volts for
+ when the BMS tries to wake up and hold a wakelock to
+ ensure a clean shutdown.
- qcom,low-soc-calculate-soc-ms : The time period between subsequent
-
SoC recalculations when the current SoC is below
- qcom,low-soc-calculate-soc-threshold.
+ qcom,low-soc-calculate-soc-threshold or when battery
+ voltage is below qcom,low-voltage-threshold.
- qcom,soc-calculate-soc-ms : The time period between subsequent SoC
recalculations when the current SoC is above or equal
qcom,low-soc-calculate-soc-threshold.
@@ -107,6 +110,7 @@
qcom,adjust-soc-low-threshold = <25>;
qcom,adjust-soc-high-threshold = <45>;
qcom,low-soc-calculate-soc-threshold = <15>;
+ qcom,low-voltage-threshold = <3420000>;
qcom,low-soc-calculate-soc-ms = <5000>;
qcom,calculate-soc-ms = <20000>;
qcom,chg-term-ua = <100000>;
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 4cd9f99..a4c05d4 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -96,6 +96,12 @@
is 8, which indicates the rx path used for audio playback
on HDMI device.
+* msm-lsm-client
+
+Required properties:
+
+ - compatible : "qcom,msm-lsm-client"
+
* msm-dai-q6
[First Level Nodes]
diff --git a/Documentation/devicetree/bindings/thermal/tsens.txt b/Documentation/devicetree/bindings/thermal/tsens.txt
index 67a986b..1388b7d 100644
--- a/Documentation/devicetree/bindings/thermal/tsens.txt
+++ b/Documentation/devicetree/bindings/thermal/tsens.txt
@@ -38,7 +38,11 @@
Optional properties:
- qcom,calibration-less-mode : If present the pre-characterized data for offsets
are used else it defaults to use calibration data from QFPROM.
-
+- qcom,tsens-local-init : If the flag is present the TSENS control registers are
+ initialized. If the boot configures the control register there is
+ no need to re-initialize them. The control registers are also
+ under a secure domain which can prevent them from being initialized
+ locally.
Example:
tsens@fc4a8000 {
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index df88caa..02c2871 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -172,115 +172,90 @@
If SSUSB_BAM is used, "ssusb" should be present.
If HSUSB_BAM is used, "hsusb" should be present.
If HSIC_BAM is used, "hsic" should be present.
-- qcom,usb-active-bam: active BAM type. Can be one of
- 0 - SSUSB_BAM
- 1 - HSUSB_BAM
- 2 - HSIC_BAM
-- qcom,usb-total-bam-num: total number of BAMs that are supported
- qcom,usb-bam-num-pipes: max number of pipes that can be used
- qcom,usb-base-address: physical base address of the BAM
A number of USB BAM pipe parameters are represented as sub-nodes:
Subnode Required:
-- label: a string describing the pipe's direction and BAM instance under use
-- qcom,usb-bam-type: BAM type. Can be one of
- 0 - SSUSB_BAM
- 1 - HSUSB_BAM
- 2 - HSIC_BAM
+- label: a string describing uniquely the usb bam pipe. The string can be
+ constracted as follows: <core>-<peer>-<direction>-<pipe num>.
+ core options: hsusb, ssusb/dwc3, hsic
+ peer options: qdss, ipa, a2
+ direction options: in (from peer to usb), out (from usb to peer)
+ pipe num options: 0..127
- qcom,usb-bam-mem-type: Type of memory used by this PIPE. Can be one of
0 - Uses SPS's dedicated pipe memory
1 - USB's private memory residing @ 'qcom,usb-base-address'
2 - System RAM allocated by driver
-- qcom,src-bam-physical-address: source BAM physical address
-- qcom,src-bam-pipe-index: source BAM pipe index
-- qcom,dst-bam-physical-address: destination BAM physical address
-- qcom,dst-bam-pipe-index: destination BAM pipe index
-- qcom,data-fifo-offset: data fifo offset address
+- qcom,bam-type: BAM type can be one of
+ 0 - SSUSB_BAM
+ 1 - HSUSB_BAM
+ 2 - HSIC_BAM
+- qcom,dir: pipe direction
+ 0 - from usb (out)
+ 1 - to usb (in)
+- qcom,pipe-num: pipe number
+- qcom,peer-bam: peer BAM can be one of
+ 0 - A2_P_BAM
+ 1 - QDSS_P_BAM
+ 2 - IPA_P_BAM
- qcom,data-fifo-size: data fifo size
-- qcom,descriptor-fifo-offset: descriptor fifo offset address
- qcom,descriptor-fifo-size: descriptor fifo size
Optional Properties for Subnode:
- qcom,reset-bam-on-connect: If present then BAM is RESET before connecting
pipe. This may be required if BAM peripheral is also reset before connect.
+- qcom,dst-bam-physical-address: destination BAM physical address
+- qcom,dst-bam-pipe-index: destination BAM pipe index
+- qcom,src-bam-physical-address: source BAM physical address
+- qcom,src-bam-pipe-index: source BAM pipe index
+- qcom,data-fifo-offset: data fifo offset address
+- qcom,descriptor-fifo-offset: descriptor fifo offset address
Optional properties :
- qcom,ignore-core-reset-ack: If present then BAM ignores ACK from USB core
while performing PIPE RESET
- qcom,disable-clk-gating: If present then disable BAM clock gating.
-
Example USB BAM controller device node:
- qcom,usbbam@f9304000 {
+ qcom,usbbam@f9a44000 {
compatible = "qcom,usb-bam-msm";
- reg = <0xf9304000 0x5000>,
- <0xf9a44000 0x11000>,
- <0xf92f880c 0x4>;
- reg-names = "ssusb", "hsusb", "qscratch_ram1_reg";
- interrupts = <0 132 0 0 135 0>;
- interrupt-names = "ssusb", "hsusb";
- qcom,usb-active-bam = <0>;
- qcom,usb-total-bam-num = <2>;
+ reg = <0xf9a44000 0x11000>;
+ reg-names = "hsusb";
+ interrupts = <0 135 0>;
+ interrupt-names = "hsusb";
qcom,usb-bam-num-pipes = <16>;
- qcom,usb-base-address = <0xf9200000>;
qcom,ignore-core-reset-ack;
+ qcom,disable-clk-gating;
+ qcom,pipe0 {
+ label = "hsusb-ipa-out-0";
+ qcom,usb-bam-mem-type = <0>;
+ qcom,bam-type = <1>;
+ qcom,dir = <0>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <2>;
+ qcom,src-bam-physical-address = <0xf9a44000>;
+ qcom,src-bam-pipe-index = <1>;
+ qcom,data-fifo-offset = <0x2200>;
+ qcom,data-fifo-size = <0x1e00>;
+ qcom,descriptor-fifo-offset = <0x2100>;
+ qcom,descriptor-fifo-size = <0x100>;
+ };
qcom,pipe1 {
- label = "usb-to-peri-qdss-dwc3";
- qcom,usb-bam-type = <0>;
- qcom,usb-bam-mem-type = <1>;
- qcom,src-bam-physical-address = <0>;
- qcom,src-bam-pipe-index = <0>;
- qcom,dst-bam-physical-address = <0>;
- qcom,dst-bam-pipe-index = <0>;
- qcom,data-fifo-offset = <0>;
- qcom,data-fifo-size = <0>;
- qcom,descriptor-fifo-offset = <0>;
- qcom,descriptor-fifo-size = <0>;
- };
-
- qcom,pipe2 {
- label = "peri-to-usb-qdss-dwc3";
- qcom,usb-bam-type = <0>;
- qcom,usb-bam-mem-type = <1>;
- qcom,src-bam-physical-address = <0xfc37C000>;
- qcom,src-bam-pipe-index = <0>;
- qcom,dst-bam-physical-address = <0xf9304000>;
- qcom,dst-bam-pipe-index = <2>;
- qcom,data-fifo-offset = <0xf0000>;
- qcom,data-fifo-size = <0x4000>;
- qcom,descriptor-fifo-offset = <0xf4000>;
- qcom,descriptor-fifo-size = <0x1400>;
- qcom,reset-bam-on-connect;
- };
-
- qcom,pipe3 {
- label = "usb-to-peri-qdss-hsusb";
- qcom,usb-bam-type = <1>;
- qcom,usb-bam-mem-type = <1>;
- qcom,src-bam-physical-address = <0>;
- qcom,src-bam-pipe-index = <0>;
- qcom,dst-bam-physical-address = <0>;
- qcom,dst-bam-pipe-index = <0>;
- qcom,data-fifo-offset = <0>;
- qcom,data-fifo-size = <0>;
- qcom,descriptor-fifo-offset = <0>;
- qcom,descriptor-fifo-size = <0>;
- };
-
- qcom,pipe4 {
- label = "peri-to-usb-qdss-hsusb";
- qcom,usb-bam-type = <1>;
- qcom,usb-bam-mem-type = <1>;
- qcom,src-bam-physical-address = <0xfc37c000>;
- qcom,src-bam-pipe-index = <0>;
+ label = "hsusb-ipa-in-0";
+ qcom,usb-bam-mem-type = <0>;
+ qcom,bam-type = <1>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <2>;
qcom,dst-bam-physical-address = <0xf9a44000>;
- qcom,dst-bam-pipe-index = <2>;
- qcom,data-fifo-offset = <0xf4000>;
- qcom,data-fifo-size = <0x1000>;
- qcom,descriptor-fifo-offset = <0xf5000>;
- qcom,descriptor-fifo-size = <0x400>;
+ qcom,dst-bam-pipe-index = <0>;
+ qcom,data-fifo-offset = <0x300>;
+ qcom,data-fifo-size = <0x1e00>;
+ qcom,descriptor-fifo-offset = <0>;
+ qcom,descriptor-fifo-size = <0x300>;
};
};
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index d456303..320c3e4a 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -111,6 +111,7 @@
qcom,calculate-soc-ms = <20000>;
qcom,chg-term-ua = <100000>;
qcom,batt-type = <0>;
+ qcom,low-voltage-threshold = <3420000>;
qcom,bms-iadc@3800 {
reg = <0x3800 0x100>;
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
index 67de6f4..fa77c35 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -239,3 +239,8 @@
mpp@a700 { /* MPP 8 */
};
};
+
+&pm8226_chg {
+ qcom,chg-charging-disabled;
+ qcom,chg-use-default-batt-values;
+};
diff --git a/arch/arm/boot/dts/msm8226-iommu-domains.dtsi b/arch/arm/boot/dts/msm8226-iommu-domains.dtsi
new file mode 100644
index 0000000..6ea5b9e
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-iommu-domains.dtsi
@@ -0,0 +1,31 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+ qcom,iommu-domains {
+ compatible = "qcom,iommu-domains";
+
+ venus_domain_ns: qcom,iommu-domain1 {
+ label = "venus_ns";
+ qcom,iommu-contexts = <&venus_ns>;
+ qcom,virtual-addr-pool = <0x40000000 0x3f000000
+ 0x7f000000 0x1000000>;
+ };
+
+ venus_domain_cp: qcom,iommu-domain2 {
+ label = "venus_cp";
+ qcom,iommu-contexts = <&venus_cp>;
+ qcom,virtual-addr-pool = <0x1000000 0x3f000000>;
+ qcom,secure-domain;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
index 2351d9c..34283e8 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -114,8 +114,8 @@
qcom,lpm-resources@0 {
reg = <0x0>;
qcom,name = "vdd-dig";
- qcom,type = <0x62706d73>; /* "smpb" */
- qcom,id = <0x02>;
+ qcom,type = <0x61706d73>; /* "smpa" */
+ qcom,id = <0x01>;
qcom,key = <0x6e726f63>; /* "corn" */
qcom,init-value = <5>; /* Super Turbo */
};
@@ -123,8 +123,8 @@
qcom,lpm-resources@1 {
reg = <0x1>;
qcom,name = "vdd-mem";
- qcom,type = <0x62706d73>; /* "smpb" */
- qcom,id = <0x01>;
+ qcom,type = <0x616F646C>; /* "ldoa" */
+ qcom,id = <0x03>;
qcom,key = <0x7675>; /* "uv" */
qcom,init-value = <1050000>; /* Super Turbo */
};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index f81afde..7a27977 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -20,7 +20,7 @@
/include/ "msm8226-bus.dtsi"
/include/ "msm8226-mdss.dtsi"
/include/ "msm8226-coresight.dtsi"
-
+/include/ "msm8226-iommu-domains.dtsi"
/ {
model = "Qualcomm MSM 8226";
compatible = "qcom,msm8226";
@@ -56,6 +56,43 @@
clock-frequency = <19200000>;
};
+ qcom,vidc@fdc00000 {
+ compatible = "qcom,msm-vidc";
+ reg = <0xfdc00000 0xff000>;
+ interrupts = <0 44 0>;
+ qcom,load-freq-tbl = <352800 160000000>,
+ <244800 133330000>,
+ <108000 66700000>;
+ qcom,hfi = "venus";
+ qcom,bus-ports = <1>;
+ qcom,reg-presets = <0xE0024 0x0>,
+ <0x80124 0x3>,
+ <0xE0020 0x5555556>,
+ <0x800B0 0x10101001>,
+ <0x800B4 0x00101010>,
+ <0x800C0 0x1010100f>,
+ <0x800C4 0x00101010>,
+ <0x800D0 0x00000010>,
+ <0x800D4 0x00000010>,
+ <0x800D8 0x00000707>;
+ qcom,enc-ddr-ab-ib = <0 0>,
+ <129000 142000>,
+ <384000 422000>,
+ <866000 953000>;
+ qcom,dec-ddr-ab-ib = <0 0>,
+ <103000 134000>,
+ <268000 348000>,
+ <505000 657000>;
+ qcom,iommu-groups = <&venus_domain_ns &venus_domain_cp>;
+ qcom,iommu-group-buffer-types = <0xfff 0x1ff>;
+ qcom,buffer-type-tz-usage-table = <0x1 0x1>,
+ <0x1fe 0x2>;
+ };
+
+ qcom,wfd {
+ compatible = "qcom,msm-wfd";
+ };
+
serial@f991f000 {
compatible = "qcom,msm-lsuart-v14";
reg = <0xf991f000 0x1000>;
@@ -422,7 +459,6 @@
compatible = "qcom,rpm-smd";
rpm-channel-name = "rpm_requests";
rpm-channel-type = <15>; /* SMD_APPS_RPM */
- rpm-standalone;
};
sdcc1: qcom,sdcc@f9824000 {
@@ -465,7 +501,6 @@
/* 190,ee0_krait_hlos_spmi_periph_irq */
/* 187,channel_0_krait_hlos_trans_done_irq */
interrupts = <0 190 0>, <0 187 0>;
- qcom,not-wakeup;
qcom,pmic-arb-ee = <0>;
qcom,pmic-arb-channel = <0>;
};
@@ -804,9 +839,6 @@
&pm8226_chg {
status = "ok";
- qcom,chg-charging-disabled;
- qcom,chg-use-default-batt-values;
-
qcom,chg-chgr@1000 {
status = "ok";
};
@@ -815,6 +847,10 @@
status = "ok";
};
+ qcom,chg-bat-if@1200 {
+ status = "ok";
+ };
+
qcom,chg-usb-chgpth@1300 {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8610-coresight.dtsi b/arch/arm/boot/dts/msm8610-coresight.dtsi
new file mode 100644
index 0000000..298cb68
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-coresight.dtsi
@@ -0,0 +1,142 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+ tmc_etr: tmc@fc326000 {
+ compatible = "arm,coresight-tmc";
+ reg = <0xfc326000 0x1000>,
+ <0xfc37c000 0x3000>;
+ reg-names = "tmc-etr-base", "tmc-etr-bam-base";
+
+ qcom,memory-reservation-type = "EBI1";
+ qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
+
+ coresight-id = <0>;
+ coresight-name = "coresight-tmc-etr";
+ coresight-nr-inports = <1>;
+ };
+
+ tpiu: tpiu@fc320000 {
+ compatible = "arm,coresight-tpiu";
+ reg = <0xfc320000 0x1000>;
+ reg-names = "tpiu-base";
+
+ coresight-id = <1>;
+ coresight-name = "coresight-tpiu";
+ coresight-nr-inports = <1>;
+ };
+
+ replicator: replicator@fc324000 {
+ compatible = "qcom,coresight-replicator";
+ reg = <0xfc324000 0x1000>;
+ reg-names = "replicator-base";
+
+ coresight-id = <2>;
+ coresight-name = "coresight-replicator";
+ coresight-nr-inports = <1>;
+ coresight-outports = <0 1>;
+ coresight-child-list = <&tmc_etr &tpiu>;
+ coresight-child-ports = <0 0>;
+ };
+
+ tmc_etf: tmc@fc325000 {
+ compatible = "arm,coresight-tmc";
+ reg = <0xfc325000 0x1000>;
+ reg-names = "tmc-etf-base";
+
+ coresight-id = <3>;
+ coresight-name = "coresight-tmc-etf";
+ coresight-nr-inports = <1>;
+ coresight-outports = <0>;
+ coresight-child-list = <&replicator>;
+ coresight-child-ports = <0>;
+ coresight-default-sink;
+ };
+
+ funnel_merg: funnel@fc323000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc323000 0x1000>;
+ reg-names = "funnel-merg-base";
+
+ coresight-id = <4>;
+ coresight-name = "coresight-funnel-merg";
+ coresight-nr-inports = <2>;
+ coresight-outports = <0>;
+ coresight-child-list = <&tmc_etf>;
+ coresight-child-ports = <0>;
+ };
+
+ funnel_in0: funnel@fc321000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc321000 0x1000>;
+ reg-names = "funnel-in0-base";
+
+ coresight-id = <5>;
+ coresight-name = "coresight-funnel-in0";
+ coresight-nr-inports = <8>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_merg>;
+ coresight-child-ports = <0>;
+ };
+
+ funnel_in1: funnel@fc322000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc322000 0x1000>;
+ reg-names = "funnel-in1-base";
+
+ coresight-id = <6>;
+ coresight-name = "coresight-funnel-in1";
+ coresight-nr-inports = <8>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_merg>;
+ coresight-child-ports = <1>;
+ };
+
+ funnel_a7ss: funnel@fc355000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc355000 0x1000>;
+ reg-names = "funnel-a7ss-base";
+
+ coresight-id = <7>;
+ coresight-name = "coresight-funnel-a7ss";
+ coresight-nr-inports = <4>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in1>;
+ coresight-child-ports = <5>;
+ };
+
+ stm: stm@fc302000 {
+ compatible = "arm,coresight-stm";
+ reg = <0xfc302000 0x1000>,
+ <0xfa280000 0x180000>;
+ reg-names = "stm-base", "stm-data-base";
+
+ coresight-id = <8>;
+ coresight-name = "coresight-stm";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in1>;
+ coresight-child-ports = <7>;
+ };
+
+ csr: csr@fc301000 {
+ compatible = "qcom,coresight-csr";
+ reg = <0xfc301000 0x1000>;
+ reg-names = "csr-base";
+
+ coresight-id = <9>;
+ coresight-name = "coresight-csr";
+ coresight-nr-inports = <0>;
+
+ qcom,blk-size = <3>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 5c78ea8..b78c3af 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -14,6 +14,7 @@
/include/ "msm-iommu-v0.dtsi"
/include/ "msm8610-ion.dtsi"
/include/ "msm-gdsc.dtsi"
+/include/ "msm8610-coresight.dtsi"
/include/ "msm8610-pm.dtsi"
/ {
@@ -235,7 +236,6 @@
compatible = "qcom,rpm-smd";
rpm-channel-name = "rpm_requests";
rpm-channel-type = <15>; /* SMD_APPS_RPM */
- rpm-standalone;
};
qcom,msm-mem-hole {
@@ -448,6 +448,7 @@
qcom,slope = <2901 2846>;
qcom,calib-mode = "fuse_map2";
qcom,calibration-less-mode;
+ qcom,tsens-local-init;
};
};
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 985b307..a35b9d2 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -370,6 +370,14 @@
hsic,ignore-cal-pad-config;
hsic,strobe-pad-offset = <0x2050>;
hsic,data-pad-offset = <0x2054>;
+
+ qcom,msm-bus,name = "hsic";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only = <0>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <85 512 0 0>,
+ <85 512 40000 160000>;
};
};
};
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index d8a1444..a0b9be6 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -420,9 +420,19 @@
qcom,pm-8x60@fe805664 {
compatible = "qcom,pm-8x60";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
reg = <0xfe805664 0x40>;
qcom,pc-mode = "tz_l2_int";
qcom,use-sync-timer;
+
+ qcom,cpu-sleep-status@f9088008 {
+ compatible = "qcom,cpu-sleep-status";
+ reg = <0xf9088008 0x4>;
+ qcom,cpu-alias-addr = <0x10000>;
+ qcom,sleep-status-mask= <0x80000>;
+ };
};
qcom,rpm-log@fc19dc00 {
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index e020fa4..2cfb192 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -417,10 +417,20 @@
qcom,pm-8x60@fe805664 {
compatible = "qcom,pm-8x60";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
reg = <0xfe805664 0x40>;
qcom,pc-mode = "tz_l2_int";
qcom,use-sync-timer;
qcom,saw-turns-off-pll;
+
+ qcom,cpu-sleep-status@f9088008{
+ compatible = "qcom,cpu-sleep-status";
+ reg = <0xf9088008 0x100>;
+ qcom,cpu-alias-addr = <0x10000>;
+ qcom,sleep-status-mask= <0x80000>;
+ };
};
qcom,rpm-log@fc19dc00 {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index d0b3c6d..ba03f79 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -36,13 +36,13 @@
memory {
- secure_mem: region@0 {
+ secure_mem: secure_region {
linux,contiguous-region;
reg = <0 0x7800000>;
label = "secure_mem";
};
- adsp_mem: region@0 {
+ adsp_mem: adsp_region {
linux,contiguous-region;
reg = <0 0x2000000>;
label = "adsp_mem";
@@ -590,6 +590,7 @@
qcom,audio-routing =
"RX_BIAS", "MCLK",
"LDO_H", "MCLK",
+ "AIF4 MAD", "MCLK",
"AMIC1", "MIC BIAS1 Internal1",
"MIC BIAS1 Internal1", "Handset Mic",
"AMIC2", "MIC BIAS2 External",
@@ -800,6 +801,10 @@
qcom,msm-dai-q6-dev-id = <8>;
};
+ qcom,msm-lsm-client {
+ compatible = "qcom,msm-lsm-client";
+ };
+
qcom,msm-dai-q6 {
compatible = "qcom,msm-dai-q6";
qcom,msm-dai-q6-sb-0-rx {
@@ -852,6 +857,11 @@
qcom,msm-dai-q6-dev-id = <16393>;
};
+ qcom,msm-dai-q6-sb-5-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16395>;
+ };
+
qcom,msm-dai-q6-bt-sco-rx {
compatible = "qcom,msm-dai-q6-dev";
qcom,msm-dai-q6-dev-id = <12288>;
@@ -1186,31 +1196,18 @@
reg-names = "ssusb", "hsusb", "qscratch_ram1_reg";
interrupts = <0 132 0 0 135 0>;
interrupt-names = "ssusb", "hsusb";
- qcom,usb-active-bam = <0>;
- qcom,usb-total-bam-num = <2>;
qcom,usb-bam-num-pipes = <16>;
qcom,usb-base-address = <0xf9200000>;
qcom,ignore-core-reset-ack;
qcom,disable-clk-gating;
- qcom,pipe1 {
- label = "usb-to-peri-qdss-dwc3";
- qcom,usb-bam-type = <0>;
+ qcom,pipe0 {
+ label = "ssusb-qdss-in-0";
qcom,usb-bam-mem-type = <1>;
- qcom,src-bam-physical-address = <0>;
- qcom,src-bam-pipe-index = <0>;
- qcom,dst-bam-physical-address = <0>;
- qcom,dst-bam-pipe-index = <0>;
- qcom,data-fifo-offset = <0>;
- qcom,data-fifo-size = <0>;
- qcom,descriptor-fifo-offset = <0>;
- qcom,descriptor-fifo-size = <0>;
- };
-
- qcom,pipe2 {
- label = "peri-to-usb-qdss-dwc3";
- qcom,usb-bam-type = <0>;
- qcom,usb-bam-mem-type = <1>;
+ qcom,bam-type = <0>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <1>;
qcom,src-bam-physical-address = <0xfc37C000>;
qcom,src-bam-pipe-index = <0>;
qcom,dst-bam-physical-address = <0xf9304000>;
@@ -1222,24 +1219,13 @@
qcom,reset-bam-on-connect;
};
- qcom,pipe3 {
- label = "usb-to-peri-qdss-hsusb";
- qcom,usb-bam-type = <1>;
+ qcom,pipe1 {
+ label = "hsusb-qdss-in-0";
qcom,usb-bam-mem-type = <1>;
- qcom,src-bam-physical-address = <0>;
- qcom,src-bam-pipe-index = <0>;
- qcom,dst-bam-physical-address = <0>;
- qcom,dst-bam-pipe-index = <0>;
- qcom,data-fifo-offset = <0>;
- qcom,data-fifo-size = <0>;
- qcom,descriptor-fifo-offset = <0>;
- qcom,descriptor-fifo-size = <0>;
- };
-
- qcom,pipe4 {
- label = "peri-to-usb-qdss-hsusb";
- qcom,usb-bam-type = <1>;
- qcom,usb-bam-mem-type = <1>;
+ qcom,bam-type = <1>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <1>;
qcom,src-bam-physical-address = <0xfc37c000>;
qcom,src-bam-pipe-index = <0>;
qcom,dst-bam-physical-address = <0xf9a44000>;
diff --git a/arch/arm/boot/dts/msm9625-v2-cdp.dts b/arch/arm/boot/dts/msm9625-v2-cdp.dts
index 244556d..09a89ab 100644
--- a/arch/arm/boot/dts/msm9625-v2-cdp.dts
+++ b/arch/arm/boot/dts/msm9625-v2-cdp.dts
@@ -42,7 +42,7 @@
wlan0: qca,wlan {
cell-index = <0>;
- compatible = "qca,ar6004-sdio";
+ compatible = "qca,ar6004-hsic";
qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
qca,ar6004-vdd-io-supply = <&pm8019_l11>;
diff --git a/arch/arm/boot/dts/msm9625-v2-mtp.dts b/arch/arm/boot/dts/msm9625-v2-mtp.dts
index bf0f539..7949080 100644
--- a/arch/arm/boot/dts/msm9625-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm9625-v2-mtp.dts
@@ -42,7 +42,7 @@
wlan0: qca,wlan {
cell-index = <0>;
- compatible = "qca,ar6004-sdio";
+ compatible = "qca,ar6004-hsic";
qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
qca,ar6004-vdd-io-supply = <&pm8019_l11>;
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 78786f6..9172029 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -123,24 +123,28 @@
qcom,msm-bus,vectors-KBps =
<85 512 0 0>,
<85 512 40000 640000>;
+ qcom,pool-64-bit-align;
+ qcom,enable-hbm;
};
qcom,usbbam@f9a44000 {
compatible = "qcom,usb-bam-msm";
- reg = <0xf9a44000 0x11000>;
- reg-names = "hsusb";
- interrupts = <0 135 0>;
- interrupt-names = "hsusb";
- qcom,usb-active-bam = <1>;
- qcom,usb-total-bam-num = <3>;
+ reg = <0xf9a44000 0x11000>,
+ <0xf9a04000 0x11000>;
+ reg-names = "hsusb", "hsic";
+ interrupts = <0 135 0 0 255 0>;
+ interrupt-names = "hsusb", "hsic";
qcom,usb-bam-num-pipes = <16>;
qcom,ignore-core-reset-ack;
qcom,disable-clk-gating;
qcom,pipe0 {
- label = "usb-to-ipa";
- qcom,usb-bam-type = <1>;
+ label = "hsusb-ipa-out-0";
qcom,usb-bam-mem-type = <0>;
+ qcom,bam-type = <1>;
+ qcom,dir = <0>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <2>;
qcom,src-bam-physical-address = <0xf9a44000>;
qcom,src-bam-pipe-index = <1>;
qcom,data-fifo-offset = <0x2200>;
@@ -149,9 +153,12 @@
qcom,descriptor-fifo-size = <0x100>;
};
qcom,pipe1 {
- label = "ipa-to-usb";
- qcom,usb-bam-type = <1>;
+ label = "hsusb-ipa-in-0";
qcom,usb-bam-mem-type = <0>;
+ qcom,bam-type = <1>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <2>;
qcom,dst-bam-physical-address = <0xf9a44000>;
qcom,dst-bam-pipe-index = <0>;
qcom,data-fifo-offset = <0x300>;
@@ -160,22 +167,12 @@
qcom,descriptor-fifo-size = <0x300>;
};
qcom,pipe2 {
- label = "usb-to-qdss-hsusb";
- qcom,usb-bam-type = <1>;
+ label = "hsusb-qdss-in-0";
qcom,usb-bam-mem-type = <0>;
- qcom,src-bam-physical-address = <0xf9a44000>;
- qcom,src-bam-pipe-index = <0>;
- qcom,dst-bam-physical-address = <0xfc37c000>;
- qcom,dst-bam-pipe-index = <0>;
- qcom,data-fifo-offset = <0>;
- qcom,data-fifo-size = <0>;
- qcom,descriptor-fifo-offset = <0>;
- qcom,descriptor-fifo-size = <0>;
- };
- qcom,pipe3 {
- label = "qdss-to-usb-hsusb";
- qcom,usb-bam-type = <1>;
- qcom,usb-bam-mem-type = <0>;
+ qcom,bam-type = <1>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <1>;
qcom,src-bam-physical-address = <0xfc37c000>;
qcom,src-bam-pipe-index = <0>;
qcom,dst-bam-physical-address = <0xf9a44000>;
@@ -185,6 +182,66 @@
qcom,descriptor-fifo-offset = <0x4000>;
qcom,descriptor-fifo-size = <0x400>;
};
+ qcom,pipe3 {
+ label = "hsic-ipa-in-0";
+ qcom,usb-bam-mem-type = <2>;
+ qcom,bam-type = <2>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <2>;
+ qcom,dst-bam-physical-address = <0xf9a04000>;
+ qcom,dst-bam-pipe-index = <3>;
+ qcom,data-fifo-size = <0xD480>;
+ qcom,descriptor-fifo-size = <0x1A80>;
+ };
+ qcom,pipe4 {
+ label = "hsic-ipa-in-1";
+ qcom,bam-type = <2>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <1>;
+ qcom,peer-bam = <2>;
+ qcom,usb-bam-mem-type = <2>;
+ qcom,dst-bam-physical-address = <0xf9a04000>;
+ qcom,dst-bam-pipe-index = <4>;
+ qcom,data-fifo-size = <0xD480>;
+ qcom,descriptor-fifo-size = <0x1A80>;
+ };
+ qcom,pipe5 {
+ label = "hsic-ipa-in-2";
+ qcom,usb-bam-mem-type = <2>;
+ qcom,bam-type = <2>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <2>;
+ qcom,peer-bam = <2>;
+ qcom,dst-bam-physical-address = <0xf9a04000>;
+ qcom,dst-bam-pipe-index = <5>;
+ qcom,data-fifo-size = <0xD480>;
+ qcom,descriptor-fifo-size = <0x1A80>;
+ };
+ qcom,pipe6 {
+ label = "hsic-ipa-in-3";
+ qcom,usb-bam-mem-type = <2>;
+ qcom,bam-type = <2>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <3>;
+ qcom,peer-bam = <2>;
+ qcom,dst-bam-physical-address = <0xf9a04000>;
+ qcom,dst-bam-pipe-index = <6>;
+ qcom,data-fifo-size = <0xD480>;
+ qcom,descriptor-fifo-size = <0x1A80>;
+ };
+ qcom,pipe7 {
+ label = "hsic-ipa-out-0";
+ qcom,usb-bam-mem-type = <2>;
+ qcom,bam-type = <2>;
+ qcom,dir = <0>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <2>;
+ qcom,src-bam-physical-address = <0xf9a04000>;
+ qcom,src-bam-pipe-index = <7>;
+ qcom,data-fifo-size = <0xD480>;
+ qcom,descriptor-fifo-size = <0x1A80>;
+ };
};
qcom,nand@f9ac0000 {
@@ -727,8 +784,8 @@
sfpb_spinlock: qcom,ipc-spinlock@fd484000 {
compatible = "qcom,ipc-spinlock-sfpb";
- reg = <0xfd484000 0x1000>;
- qcom,num-locks = <32>;
+ reg = <0xfd484000 0x400>;
+ qcom,num-locks = <8>;
};
ldrex_spinlock: qcom,ipc-spinlock@fa00000 {
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index dc806e3..cfdff6f 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -182,6 +182,7 @@
CONFIG_NET_CLS_FW=y
CONFIG_SYNC=y
CONFIG_SW_SYNC=y
+CONFIG_CMA=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_MD=y
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 833b213..20c461d 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -1577,8 +1577,6 @@
{
DMUX_LOG_KERR("%s: modem timeout: BAM DMUX disabled\n", __func__);
in_global_reset = 1;
- if (get_restart_level() <= RESET_SOC)
- DMUX_LOG_KERR("%s: ssrestart not enabled\n", __func__);
return 1;
}
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index f609bbc..50f4fd7 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -625,8 +625,13 @@
#define USB_BAM_PHY_BASE 0x12502000
#define HSIC_BAM_PHY_BASE 0x12542000
#define A2_BAM_PHY_BASE 0x124C2000
-static struct usb_bam_pipe_connect msm_usb_bam_connections[MAX_BAMS][8][2] = {
- [HSUSB_BAM][0][USB_TO_PEER_PERIPHERAL] = {
+static struct usb_bam_pipe_connect msm_usb_bam_connections[] = {
+ {
+ .name = "hsusb-a2-out-0",
+ .bam_type = HSUSB_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = USB_TO_PEER_PERIPHERAL,
+ .pipe_num = 0,
.src_phy_addr = USB_BAM_PHY_BASE,
.src_pipe_index = 11,
.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -636,7 +641,12 @@
.desc_fifo_base_offset = 0x1700,
.desc_fifo_size = 0x300,
},
- [HSUSB_BAM][0][PEER_PERIPHERAL_TO_USB] = {
+ {
+ .name = "hsusb-a2-in-0",
+ .bam_type = HSUSB_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = PEER_PERIPHERAL_TO_USB,
+ .pipe_num = 0,
.src_phy_addr = A2_BAM_PHY_BASE,
.src_pipe_index = 1,
.dst_phy_addr = USB_BAM_PHY_BASE,
@@ -646,7 +656,12 @@
.desc_fifo_base_offset = 0x1000,
.desc_fifo_size = 0x100,
},
- [HSUSB_BAM][1][USB_TO_PEER_PERIPHERAL] = {
+ {
+ .name = "hsusb-a2-out-1",
+ .bam_type = HSUSB_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = USB_TO_PEER_PERIPHERAL,
+ .pipe_num = 1,
.src_phy_addr = USB_BAM_PHY_BASE,
.src_pipe_index = 13,
.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -656,7 +671,12 @@
.desc_fifo_base_offset = 0x2700,
.desc_fifo_size = 0x300,
},
- [HSUSB_BAM][1][PEER_PERIPHERAL_TO_USB] = {
+ {
+ .name = "hsusb-a2-in-1",
+ .bam_type = HSUSB_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = PEER_PERIPHERAL_TO_USB,
+ .pipe_num = 1,
.src_phy_addr = A2_BAM_PHY_BASE,
.src_pipe_index = 3,
.dst_phy_addr = USB_BAM_PHY_BASE,
@@ -666,7 +686,12 @@
.desc_fifo_base_offset = 0x2000,
.desc_fifo_size = 0x100,
},
- [HSUSB_BAM][2][USB_TO_PEER_PERIPHERAL] = {
+ {
+ .name = "hsusb-a2-out-2",
+ .bam_type = HSUSB_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = USB_TO_PEER_PERIPHERAL,
+ .pipe_num = 2,
.src_phy_addr = USB_BAM_PHY_BASE,
.src_pipe_index = 15,
.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -676,7 +701,12 @@
.desc_fifo_base_offset = 0x3700,
.desc_fifo_size = 0x300,
},
- [HSUSB_BAM][2][PEER_PERIPHERAL_TO_USB] = {
+ {
+ .name = "hsusb-a2-in-2",
+ .bam_type = HSUSB_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = PEER_PERIPHERAL_TO_USB,
+ .pipe_num = 2,
.src_phy_addr = A2_BAM_PHY_BASE,
.src_pipe_index = 5,
.dst_phy_addr = USB_BAM_PHY_BASE,
@@ -686,7 +716,12 @@
.desc_fifo_base_offset = 0x3000,
.desc_fifo_size = 0x100,
},
- [HSIC_BAM][0][USB_TO_PEER_PERIPHERAL] = {
+ {
+ .name = "hsic-a2-out-0",
+ .bam_type = HSIC_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = USB_TO_PEER_PERIPHERAL,
+ .pipe_num = 0,
.src_phy_addr = HSIC_BAM_PHY_BASE,
.src_pipe_index = 1,
.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -696,7 +731,12 @@
.desc_fifo_base_offset = 0x1700,
.desc_fifo_size = 0x300,
},
- [HSIC_BAM][0][PEER_PERIPHERAL_TO_USB] = {
+ {
+ .name = "hsic-a2-in-0",
+ .bam_type = HSIC_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = PEER_PERIPHERAL_TO_USB,
+ .pipe_num = 0,
.src_phy_addr = A2_BAM_PHY_BASE,
.src_pipe_index = 1,
.dst_phy_addr = HSIC_BAM_PHY_BASE,
@@ -706,7 +746,12 @@
.desc_fifo_base_offset = 0x1000,
.desc_fifo_size = 0x100,
},
- [HSIC_BAM][1][USB_TO_PEER_PERIPHERAL] = {
+ {
+ .name = "hsic-a2-out-1",
+ .bam_type = HSIC_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = USB_TO_PEER_PERIPHERAL,
+ .pipe_num = 1,
.src_phy_addr = HSIC_BAM_PHY_BASE,
.src_pipe_index = 3,
.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -716,7 +761,12 @@
.desc_fifo_base_offset = 0x2700,
.desc_fifo_size = 0x300,
},
- [HSIC_BAM][1][PEER_PERIPHERAL_TO_USB] = {
+ {
+ .name = "hsic-a2-in-1",
+ .bam_type = HSIC_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = PEER_PERIPHERAL_TO_USB,
+ .pipe_num = 1,
.src_phy_addr = A2_BAM_PHY_BASE,
.src_pipe_index = 3,
.dst_phy_addr = HSIC_BAM_PHY_BASE,
@@ -726,7 +776,12 @@
.desc_fifo_base_offset = 0x2000,
.desc_fifo_size = 0x100,
},
- [HSIC_BAM][2][USB_TO_PEER_PERIPHERAL] = {
+ {
+ .name = "hsic-a2-out-2",
+ .bam_type = HSIC_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = USB_TO_PEER_PERIPHERAL,
+ .pipe_num = 2,
.src_phy_addr = HSIC_BAM_PHY_BASE,
.src_pipe_index = 5,
.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -736,7 +791,12 @@
.desc_fifo_base_offset = 0x3700,
.desc_fifo_size = 0x300,
},
- [HSIC_BAM][2][PEER_PERIPHERAL_TO_USB] = {
+ {
+ .name = "hsic-a2-in-2",
+ .bam_type = HSIC_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = PEER_PERIPHERAL_TO_USB,
+ .pipe_num = 2,
.src_phy_addr = A2_BAM_PHY_BASE,
.src_pipe_index = 5,
.dst_phy_addr = HSIC_BAM_PHY_BASE,
@@ -749,12 +809,9 @@
};
static struct msm_usb_bam_platform_data msm_usb_bam_pdata = {
- .connections = &msm_usb_bam_connections[0][0][0],
-#ifndef CONFIG_USB_CI13XXX_MSM_HSIC
- .usb_active_bam = HSUSB_BAM,
-#else
- .usb_active_bam = HSIC_BAM,
-#endif
+ .connections = &msm_usb_bam_connections[0],
+ .max_connections = sizeof(msm_usb_bam_connections) /
+ sizeof(struct usb_bam_pipe_connect),
.usb_bam_num_pipes = 16,
};
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 78e3259..0657c21 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -4851,6 +4851,7 @@
CLK_LOOKUP("phy_clk", gcc_usb_hsic_clk.c, "msm_hsic_host"),
CLK_LOOKUP("cal_clk", gcc_usb_hsic_io_cal_clk.c, "msm_hsic_host"),
CLK_LOOKUP("core_clk", gcc_usb_hsic_system_clk.c, "msm_hsic_host"),
+ CLK_LOOKUP("osr_clk", div_clk1.c, "msm-dai-q6-dev.16384"),
CLK_LOOKUP("ref_clk", div_clk2.c, "msm_smsc_hub"),
CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c, "msm_ehci_host"),
CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c, "msm_ehci_host"),
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index c82058b..d2be1f9 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -529,6 +529,18 @@
BUG();
}
+ if (!pll_clk_is_enabled(c))
+ return HANDOFF_DISABLED_CLK;
+
+ /*
+ * Do not call pll_clk_enable() since that function can assume
+ * the PLL is not in use when it's called.
+ */
+ remote_spin_lock(&pll_lock);
+ pll_control->pll[PLL_BASE + pll->id].votes |= BIT(1);
+ pll_control->pll[PLL_BASE + pll->id].on = 1;
+ remote_spin_unlock(&pll_lock);
+
return HANDOFF_ENABLED_CLK;
}
@@ -572,10 +584,22 @@
spin_unlock_irqrestore(&soft_vote_lock, flags);
}
+static enum handoff pll_acpu_vote_clk_handoff(struct clk *c)
+{
+ if (pll_vote_clk_handoff(c) == HANDOFF_DISABLED_CLK)
+ return HANDOFF_DISABLED_CLK;
+
+ if (pll_acpu_vote_clk_enable(c))
+ return HANDOFF_DISABLED_CLK;
+
+ return HANDOFF_ENABLED_CLK;
+}
+
struct clk_ops clk_ops_pll_acpu_vote = {
.enable = pll_acpu_vote_clk_enable,
.disable = pll_acpu_vote_clk_disable,
.is_enabled = pll_vote_clk_is_enabled,
+ .handoff = pll_acpu_vote_clk_handoff,
};
static void __init __set_fsm_mode(void __iomem *mode_reg,
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index 5cd5057..0e97c27 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -70,6 +70,11 @@
int platform_cpu_kill(unsigned int cpu)
{
+ int ret;
+
+ ret = msm_pm_wait_cpu_shutdown(cpu);
+ if (ret)
+ return 0;
return 1;
}
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
index 59908e6..c21f6e5 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -82,6 +82,7 @@
#define APR_SVC_ADSP_CVS 0x0A
#define APR_SVC_ADSP_CVP 0x0B
#define APR_SVC_USM 0x0C
+#define APR_SVC_LSM 0x0D
#define APR_SVC_VIDC 0x16
#define APR_SVC_MAX 0x17
diff --git a/arch/arm/mach-msm/include/mach/subsystem_restart.h b/arch/arm/mach-msm/include/mach/subsystem_restart.h
index 1f6ca66..67f643e 100644
--- a/arch/arm/mach-msm/include/mach/subsystem_restart.h
+++ b/arch/arm/mach-msm/include/mach/subsystem_restart.h
@@ -21,9 +21,8 @@
struct subsys_device;
enum {
- RESET_SOC = 1,
+ RESET_SOC = 0,
RESET_SUBSYS_COUPLED,
- RESET_SUBSYS_INDEPENDENT,
RESET_LEVEL_MAX
};
@@ -60,7 +59,7 @@
#if defined(CONFIG_MSM_SUBSYSTEM_RESTART)
-extern int get_restart_level(void);
+extern int subsys_get_restart_level(struct subsys_device *dev);
extern int subsystem_restart_dev(struct subsys_device *dev);
extern int subsystem_restart(const char *name);
extern int subsystem_crashed(const char *name);
@@ -75,7 +74,7 @@
#else
-static inline int get_restart_level(void)
+static inline int subsys_get_restart_level(struct subsys_device *dev)
{
return 0;
}
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index b3fb8af..5a77d99 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,22 +14,36 @@
#define _USB_BAM_H_
#include "sps.h"
#include <mach/ipa.h>
+#include <linux/usb/msm_hsusb.h>
-/**
- * SPS Pipes direction.
- *
- * USB_TO_PEER_PERIPHERAL USB (as Producer) to other
- * peer peripheral.
- * PEER_PERIPHERAL_TO_USB Other Peripheral to
- * USB (as consumer).
- */
+enum usb_bam {
+ SSUSB_BAM = 0,
+ HSUSB_BAM,
+ HSIC_BAM,
+ MAX_BAMS,
+};
+
+enum peer_bam {
+ A2_P_BAM = 0,
+ QDSS_P_BAM,
+ IPA_P_BAM,
+ MAX_PEER_BAMS,
+};
+
enum usb_bam_pipe_dir {
USB_TO_PEER_PERIPHERAL,
PEER_PERIPHERAL_TO_USB,
};
+enum usb_pipe_mem_type {
+ SPS_PIPE_MEM = 0, /* Default, SPS dedicated pipe memory */
+ USB_PRIVATE_MEM, /* USB's private memory */
+ SYSTEM_MEM, /* System RAM, requires allocation */
+};
+
struct usb_bam_connect_ipa_params {
- u8 idx;
+ u8 src_idx;
+ u8 dst_idx;
u32 *src_pipe;
u32 *dst_pipe;
enum usb_bam_pipe_dir dir;
@@ -44,29 +58,100 @@
unsigned long data);
};
+/**
+* struct usb_bam_event_info: suspend/resume event information.
+* @event: holds event data.
+* @callback: suspend/resume callback.
+* @param: port num (for suspend) or NULL (for resume).
+* @event_w: holds work queue parameters.
+*/
+struct usb_bam_event_info {
+ struct sps_register_event event;
+ int (*callback)(void *);
+ void *param;
+ struct work_struct event_w;
+};
+
+/**
+* struct usb_bam_pipe_connect: pipe connection information
+* between USB/HSIC BAM and another BAM. USB/HSIC BAM can be
+* either src BAM or dst BAM
+* @name: pipe description.
+* @mem_type: type of memory used for BAM FIFOs
+* @src_phy_addr: src bam physical address.
+* @src_pipe_index: src bam pipe index.
+* @dst_phy_addr: dst bam physical address.
+* @dst_pipe_index: dst bam pipe index.
+* @data_fifo_base_offset: data fifo offset.
+* @data_fifo_size: data fifo size.
+* @desc_fifo_base_offset: descriptor fifo offset.
+* @desc_fifo_size: descriptor fifo size.
+* @data_mem_buf: data fifo buffer.
+* @desc_mem_buf: descriptor fifo buffer.
+* @wake_event: event for wakeup.
+* @enabled: true if pipe is enabled.
+*/
+struct usb_bam_pipe_connect {
+ const char *name;
+ u32 pipe_num;
+ enum usb_pipe_mem_type mem_type;
+ enum usb_bam_pipe_dir dir;
+ enum usb_bam bam_type;
+ enum peer_bam peer_bam;
+ u32 src_phy_addr;
+ u32 src_pipe_index;
+ u32 dst_phy_addr;
+ u32 dst_pipe_index;
+ u32 data_fifo_base_offset;
+ u32 data_fifo_size;
+ u32 desc_fifo_base_offset;
+ u32 desc_fifo_size;
+ struct sps_mem_buffer data_mem_buf;
+ struct sps_mem_buffer desc_mem_buf;
+ struct usb_bam_event_info wake_event;
+ bool enabled;
+};
+
+/**
+ * struct msm_usb_bam_platform_data: pipe connection information
+ * between USB/HSIC BAM and another BAM. USB/HSIC BAM can be
+ * either src BAM or dst BAM
+ * @connections: holds all pipe connections data.
+ * @usb_bam_num_pipes: max number of pipes to use.
+ * @active_conn_num: number of active pipe connections.
+ * @usb_base_address: BAM physical address.
+ * @ignore_core_reset_ack: BAM can ignore ACK from USB core during PIPE RESET
+ * @disable_clk_gating: Disable clock gating
+ */
+struct msm_usb_bam_platform_data {
+ struct usb_bam_pipe_connect *connections;
+ u8 max_connections;
+ int usb_bam_num_pipes;
+ u32 usb_base_address;
+ bool ignore_core_reset_ack;
+ bool reset_on_connect[MAX_BAMS];
+ bool disable_clk_gating;
+};
+
#ifdef CONFIG_USB_BAM
/**
- * Connect USB-to-Periperal SPS connection.
+ * Connect USB-to-Peripheral SPS connection.
*
- * This function returns the allocated pipes number.
+ * This function returns the allocated pipe number.
*
* @idx - Connection index.
*
- * @src_pipe_idx - allocated pipe index - USB as a
- * source (output)
- *
- * @dst_pipe_idx - allocated pipe index - USB as a
- * destination (output)
+ * @bam_pipe_idx - allocated pipe index.
*
* @return 0 on success, negative value on error
*
*/
-int usb_bam_connect(u8 idx, u32 *src_pipe_idx, u32 *dst_pipe_idx);
+int usb_bam_connect(u8 idx, u32 *bam_pipe_idx);
/**
* Connect USB-to-IPA SPS connection.
*
- * This function returns the allocated pipes number adn clnt handles.
+ * This function returns the allocated pipes number and clnt handles.
*
* @ipa_params - in/out parameters
*
@@ -78,14 +163,12 @@
/**
* Disconnect USB-to-IPA SPS connection.
*
- * @idx - Connection index.
- *
* @ipa_params - in/out parameters
*
* @return 0 on success, negative value on error
*
*/
-int usb_bam_disconnect_ipa(u8 idx,
+int usb_bam_disconnect_ipa(
struct usb_bam_connect_ipa_params *ipa_params);
/**
@@ -99,13 +182,11 @@
*
*/
int usb_bam_register_wake_cb(u8 idx,
- int (*callback)(void *), void* param);
+ int (*callback)(void *), void *param);
/**
* Register a callback for peer BAM reset.
*
- * @idx - Connection index.
- *
* @callback - the callback function that will be called in USB
* driver upon a peer bam reset
*
@@ -114,8 +195,7 @@
* @return 0 on success, negative value on error
*
*/
-int usb_bam_register_peer_reset_cb(u8 idx,
- int (*callback)(void *), void *param);
+int usb_bam_register_peer_reset_cb(int (*callback)(void *), void *param);
/**
* Disconnect USB-to-Periperal SPS connection.
@@ -129,9 +209,7 @@
/**
* Returns usb bam connection parameters.
*
- * @conn_idx - Connection index.
- *
- * @usb_bam_pipe_dir - Usb pipe direction to/from peripheral.
+ * @idx - Connection index.
*
* @usb_bam_handle - Usb bam handle.
*
@@ -143,16 +221,17 @@
*
* @data_fifo - Data fifo parameters.
*
+ * @return pipe index on success, negative value on error.
*/
-void get_bam2bam_connection_info(u8 conn_idx, enum usb_bam_pipe_dir pipe_dir,
+int get_bam2bam_connection_info(u8 idx,
u32 *usb_bam_handle, u32 *usb_bam_pipe_idx, u32 *peer_pipe_idx,
struct sps_mem_buffer *desc_fifo, struct sps_mem_buffer *data_fifo);
/**
- * Resets the entire USB BAM.
+ * Resets the USB BAM that has A2 pipes
*
*/
-int usb_bam_reset(void);
+int usb_bam_a2_reset(void);
/**
* Indicates if the client of the USB BAM is ready to start
@@ -162,9 +241,41 @@
*
*/
int usb_bam_client_ready(bool ready);
+/**
+* Returns qdss index from the connections array.
+*
+* @num - The qdss pipe number.
+*
+* @return pipe index on success, negative value on error
+*/
+int usb_bam_get_qdss_idx(u8 num);
+
+/**
+* Saves qdss core number.
+*
+* @qdss_core - The qdss core name.
+*/
+void usb_bam_set_qdss_core(const char *qdss_core);
+
+/**
+* Indicates if the client of the USB BAM is ready to start
+* sending/receiving transfers.
+*
+* @name - Core name (ssusb/hsusb/hsic).
+*
+* @client - Usb pipe peer (a2, ipa, qdss...)
+*
+* @dir - In (from peer to usb) or out (from usb to peer)
+*
+* @num - Pipe number.
+*
+* @return 0 on success, negative value on error
+*/
+int usb_bam_get_connection_idx(const char *name, enum peer_bam client,
+ enum usb_bam_pipe_dir dir, u32 num);
#else
-static inline int usb_bam_connect(u8 idx, u32 *src_pipe_idx, u32 *dst_pipe_idx)
+static inline int usb_bam_connect(u8 idx, u32 *bam_pipe_idx)
{
return -ENODEV;
}
@@ -175,7 +286,7 @@
return -ENODEV;
}
-static inline int usb_bam_disconnect_ipa(u8 idx,
+static inline int usb_bam_disconnect_ipa(
struct usb_bam_connect_ipa_params *ipa_params)
{
return -ENODEV;
@@ -187,8 +298,8 @@
return -ENODEV;
}
-static inline int usb_bam_register_peer_reset_cb(u8 idx,
- int (*callback)(void *), void *param)
+static inline int usb_bam_register_peer_reset_cb(
+ int (*callback)(void *), void *param)
{
return -ENODEV;
}
@@ -198,15 +309,14 @@
return -ENODEV;
}
-static inline void get_bam2bam_connection_info(u8 conn_idx,
- enum usb_bam_pipe_dir pipe_dir, u32 *usb_bam_handle,
- u32 *usb_bam_pipe_idx, u32 *peer_pipe_idx,
+static inline int get_bam2bam_connection_info(u8 idx,
+ u32 *usb_bam_handle, u32 *usb_bam_pipe_idx, u32 *peer_pipe_idx,
struct sps_mem_buffer *desc_fifo, struct sps_mem_buffer *data_fifo)
{
- return;
+ return -ENODEV;
}
-static inline int usb_bam_reset(void)
+static inline int usb_bam_a2_reset(void)
{
return -ENODEV;
}
@@ -216,5 +326,20 @@
return -ENODEV;
}
+static inline int usb_bam_get_qdss_idx(u8 num)
+{
+ return -ENODEV;
+}
+
+static inline void usb_bam_set_qdss_core(const char *qdss_core)
+{
+ return;
+}
+
+static inline int usb_bam_get_connection_idx(const char *name,
+ enum peer_bam client, enum usb_bam_pipe_dir dir, u32 num)
+{
+ return -ENODEV;
+}
#endif
#endif /* _USB_BAM_H_ */
diff --git a/arch/arm/mach-msm/mdm.c b/arch/arm/mach-msm/mdm.c
index fd8c878..7474215 100644
--- a/arch/arm/mach-msm/mdm.c
+++ b/arch/arm/mach-msm/mdm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -119,7 +119,7 @@
CHARM_DBG("%s: setting AP2MDM_ERRFATAL high for a non graceful reset\n",
__func__);
- if (get_restart_level() == RESET_SOC)
+ if (subsys_get_restart_level(charm_subsys) == RESET_SOC)
pm8xxx_stay_on();
charm_disable_irqs();
@@ -237,7 +237,7 @@
static void charm_fatal_fn(struct work_struct *work)
{
pr_info("Reseting the charm due to an errfatal\n");
- if (get_restart_level() == RESET_SOC)
+ if (subsys_get_restart_level(charm_subsys) == RESET_SOC)
pm8xxx_stay_on();
subsystem_restart_dev(charm_subsys);
}
diff --git a/arch/arm/mach-msm/msm_rtb.c b/arch/arm/mach-msm/msm_rtb.c
index e797e2e..fdf39be 100644
--- a/arch/arm/mach-msm/msm_rtb.c
+++ b/arch/arm/mach-msm/msm_rtb.c
@@ -55,7 +55,7 @@
struct msm_rtb_state {
struct msm_rtb_layout *rtb;
- unsigned long phys;
+ phys_addr_t phys;
int nentries;
int size;
int enabled;
diff --git a/arch/arm/mach-msm/pil-dsps.c b/arch/arm/mach-msm/pil-dsps.c
index 0630e6a..65d60d6 100644
--- a/arch/arm/mach-msm/pil-dsps.c
+++ b/arch/arm/mach-msm/pil-dsps.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -142,9 +142,6 @@
static void dsps_restart_handler(struct dsps_data *drv)
{
- pr_debug("%s: Restart lvl %d\n",
- __func__, get_restart_level());
-
if (atomic_add_return(1, &drv->crash_in_progress) > 1) {
pr_err("%s: DSPS already resetting. Count %d\n", __func__,
atomic_read(&drv->crash_in_progress));
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index a22d664..717c057 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -25,7 +25,9 @@
#include <linux/smp.h>
#include <linux/suspend.h>
#include <linux/tick.h>
+#include <linux/delay.h>
#include <linux/platform_device.h>
+#include <linux/of_platform.h>
#include <linux/regulator/krait-regulator.h>
#include <mach/msm_iomap.h>
#include <mach/socinfo.h>
@@ -127,6 +129,7 @@
static bool msm_pm_retention_calls_tz;
static uint32_t msm_pm_max_sleep_time;
static bool msm_no_ramp_down_pc;
+static struct msm_pm_sleep_status_data *msm_pm_slp_sts;
static int msm_pm_get_pc_mode(struct device_node *node,
const char *key, uint32_t *pc_mode_val)
@@ -953,6 +956,32 @@
return sleep_mode;
}
+int msm_pm_wait_cpu_shutdown(unsigned int cpu)
+{
+ int timeout = 10;
+
+ if (!msm_pm_slp_sts)
+ return 0;
+ if (!msm_pm_slp_sts[cpu].base_addr)
+ return 0;
+ while (timeout--) {
+ /*
+ * Check for the SPM of the core being hotplugged to set
+ * its sleep state.The SPM sleep state indicates that the
+ * core has been power collapsed.
+ */
+ int acc_sts = __raw_readl(msm_pm_slp_sts[cpu].base_addr);
+
+ if (acc_sts & msm_pm_slp_sts[cpu].mask)
+ return 0;
+ usleep(100);
+ }
+
+ pr_info("%s(): Timed out waiting for CPU %u SPM to enter sleep state",
+ __func__, cpu);
+ return -EBUSY;
+}
+
void msm_pm_cpu_enter_lowpower(unsigned int cpu)
{
int i;
@@ -1109,6 +1138,93 @@
.enter = msm_pm_enter,
.valid = suspend_valid_only_mem,
};
+static int __devinit msm_cpu_status_probe(struct platform_device *pdev)
+{
+ struct msm_pm_sleep_status_data *pdata;
+ char *key;
+ u32 cpu;
+
+ if (!pdev)
+ return -EFAULT;
+
+ msm_pm_slp_sts =
+ kzalloc(sizeof(*msm_pm_slp_sts) * num_possible_cpus(),
+ GFP_KERNEL);
+
+ if (!msm_pm_slp_sts)
+ return -ENOMEM;
+
+ if (pdev->dev.of_node) {
+ struct resource *res;
+ u32 offset;
+ int rc;
+ u32 mask;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ goto fail_free_mem;
+
+ key = "qcom,cpu-alias-addr";
+ rc = of_property_read_u32(pdev->dev.of_node, key, &offset);
+
+ if (rc)
+ goto fail_free_mem;
+
+ key = "qcom,sleep-status-mask";
+ rc = of_property_read_u32(pdev->dev.of_node, key,
+ &mask);
+ if (rc)
+ goto fail_free_mem;
+
+ for_each_possible_cpu(cpu) {
+ msm_pm_slp_sts[cpu].base_addr =
+ ioremap(res->start + cpu * offset,
+ resource_size(res));
+ msm_pm_slp_sts[cpu].mask = mask;
+
+ if (!msm_pm_slp_sts[cpu].base_addr)
+ goto failed_of_node;
+ }
+
+ } else {
+ pdata = pdev->dev.platform_data;
+ if (!pdev->dev.platform_data)
+ goto fail_free_mem;
+
+ for_each_possible_cpu(cpu) {
+ msm_pm_slp_sts[cpu].base_addr =
+ pdata->base_addr + cpu * pdata->cpu_offset;
+ msm_pm_slp_sts[cpu].mask = pdata->mask;
+ }
+ }
+
+ return 0;
+
+failed_of_node:
+ pr_info("%s(): Failed to key=%s\n", __func__, key);
+ for_each_possible_cpu(cpu) {
+ if (msm_pm_slp_sts[cpu].base_addr)
+ iounmap(msm_pm_slp_sts[cpu].base_addr);
+ }
+fail_free_mem:
+ kfree(msm_pm_slp_sts);
+ return -EINVAL;
+
+};
+
+static struct of_device_id msm_slp_sts_match_tbl[] = {
+ {.compatible = "qcom,cpu-sleep-status"},
+ {},
+};
+
+static struct platform_driver msm_cpu_status_driver = {
+ .probe = msm_cpu_status_probe,
+ .driver = {
+ .name = "cpu_slp_status",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_slp_sts_match_tbl,
+ },
+};
static int __devinit msm_pm_init(void)
{
@@ -1378,6 +1494,9 @@
pm_8x60_probe_done:
msm_pm_init();
+ if (pdev->dev.of_node)
+ of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+
return ret;
}
@@ -1397,6 +1516,16 @@
static int __init msm_pm_8x60_init(void)
{
+ int rc;
+
+ rc = platform_driver_register(&msm_cpu_status_driver);
+
+ if (rc) {
+ pr_err("%s(): failed to register driver %s\n", __func__,
+ msm_cpu_status_driver.driver.name);
+ return rc;
+ }
+
return platform_driver_register(&msm_pm_8x60_driver);
}
device_initcall(msm_pm_8x60_init);
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 793b778..8a043d8 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -135,9 +135,11 @@
#ifdef CONFIG_MSM_PM8X60
void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops);
+int msm_pm_wait_cpu_shutdown(unsigned int cpu);
#else
static inline void msm_pm_set_rpm_wakeup_irq(unsigned int irq) {}
static inline void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops) {}
+static inline int msm_pm_wait_cpu_shutdown(unsigned int cpu) { return 0; }
#endif
#ifdef CONFIG_HOTPLUG_CPU
int msm_platform_secondary_init(unsigned int cpu);
diff --git a/arch/arm/mach-msm/qdsp6v2/apr.c b/arch/arm/mach-msm/qdsp6v2/apr.c
index 4c106c5..6e60db1 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -26,6 +26,7 @@
#include <linux/sysfs.h>
#include <linux/device.h>
#include <linux/slab.h>
+#include <sound/apr_audio-v2.h>
#include <asm/mach-types.h>
#include <mach/subsystem_restart.h>
#include <mach/msm_smd.h>
@@ -114,6 +115,11 @@
.name = "VIDC",
.idx = 9,
.id = APR_SVC_VIDC,
+ },
+ {
+ .name = "LSM",
+ .idx = 9,
+ .id = APR_SVC_LSM,
.client_id = APR_CLIENT_AUDIO,
},
};
@@ -280,7 +286,6 @@
return -ENETRESET;
}
-
spin_lock_irqsave(&svc->w_lock, flags);
dest_id = svc->dest_id;
client_id = svc->client_id;
@@ -391,7 +396,8 @@
svc == APR_SVC_ADM || svc == APR_SVC_ADSP_CORE ||
svc == APR_SVC_USM ||
svc == APR_SVC_TEST_CLIENT || svc == APR_SVC_ADSP_MVM ||
- svc == APR_SVC_ADSP_CVS || svc == APR_SVC_ADSP_CVP)
+ svc == APR_SVC_ADSP_CVS || svc == APR_SVC_ADSP_CVP ||
+ svc == APR_SVC_LSM)
clnt = APR_CLIENT_AUDIO;
else if (svc == APR_SVC_VIDC)
clnt = APR_CLIENT_AUDIO;
diff --git a/arch/arm/mach-msm/ramdump.h b/arch/arm/mach-msm/ramdump.h
index e43ca12..3a960a1 100644
--- a/arch/arm/mach-msm/ramdump.h
+++ b/arch/arm/mach-msm/ramdump.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -20,6 +20,7 @@
unsigned long size;
};
+#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
void *create_ramdump_device(const char *dev_name, struct device *parent);
void destroy_ramdump_device(void *dev);
int do_ramdump(void *handle, struct ramdump_segment *segments,
@@ -27,4 +28,28 @@
int do_elf_ramdump(void *handle, struct ramdump_segment *segments,
int nsegments);
+#else
+static inline void *create_ramdump_device(const char *dev_name,
+ struct device *parent)
+{
+ return NULL;
+}
+
+static inline void destroy_ramdump_device(void *dev)
+{
+}
+
+static inline int do_ramdump(void *handle, struct ramdump_segment *segments,
+ int nsegments)
+{
+ return -ENODEV;
+}
+
+static inline int do_elf_ramdump(void *handle, struct ramdump_segment *segments,
+ int nsegments)
+{
+ return -ENODEV;
+}
+#endif /* CONFIG_MSM_SUBSYSTEM_RESTART */
+
#endif
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index cffb211..40ef20e 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -49,6 +49,7 @@
#include "smd_private.h"
#include "modem_notifier.h"
+#include "ramdump.h"
#if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_MSM8X60) \
|| defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_FSM9XXX) \
@@ -178,7 +179,10 @@
};
static uint32_t num_smem_areas;
static struct smem_area *smem_areas;
+static struct ramdump_segment *smem_ramdump_segments;
+static void *smem_ramdump_dev;
static void *smem_range_check(phys_addr_t base, unsigned offset);
+static void *smd_dev;
struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
@@ -977,10 +981,6 @@
SMx_POWER_INFO("%s: starting reset\n", __func__);
- /* release any held spinlocks */
- remote_spin_release(&remote_spinlock, restart_pid);
- remote_spin_release_all(restart_pid);
-
shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64);
if (!shared) {
pr_err("%s: allocation table not initialized\n", __func__);
@@ -3720,6 +3720,7 @@
struct device_node *node;
int ret;
const char *compatible;
+ struct ramdump_segment *ramdump_segments_tmp;
int subnode_num = 0;
resource_size_t irq_out_size;
@@ -3757,13 +3758,33 @@
}
}
+ /* initialize SSR ramdump regions */
+ key = "smem";
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
+ if (!r) {
+ pr_err("%s: missing '%s'\n", __func__, key);
+ return -ENODEV;
+ }
+ ramdump_segments_tmp = kmalloc_array(num_smem_areas + 1,
+ sizeof(struct ramdump_segment), GFP_KERNEL);
+
+ if (!ramdump_segments_tmp) {
+ pr_err("%s: ramdump segment kmalloc failed\n", __func__);
+ ret = -ENOMEM;
+ goto free_smem_areas;
+ }
+ ramdump_segments_tmp[0].address = r->start;
+ ramdump_segments_tmp[0].size = resource_size(r);
+
if (num_smem_areas) {
+
smem_areas = kmalloc(sizeof(struct smem_area) * num_smem_areas,
GFP_KERNEL);
+
if (!smem_areas) {
pr_err("%s: smem areas kmalloc failed\n", __func__);
- num_smem_areas = 0;
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto free_smem_areas;
}
count = 1;
while (1) {
@@ -3775,6 +3796,16 @@
break;
aux_mem_base = r->start;
aux_mem_size = resource_size(r);
+
+ /*
+ * Add to ram-dumps segments.
+ * ramdump_segments_tmp[0] is the main SMEM region,
+ * so auxiliary segments are indexed by count
+ * instead of count - 1.
+ */
+ ramdump_segments_tmp[count].address = aux_mem_base;
+ ramdump_segments_tmp[count].size = aux_mem_size;
+
SMD_DBG("%s: %s = %pa %pa", __func__, temp_string,
&aux_mem_base, &aux_mem_size);
smem_areas[count - 1].phys_addr = aux_mem_base;
@@ -3822,6 +3853,7 @@
++subnode_num;
}
+ smem_ramdump_segments = ramdump_segments_tmp;
return 0;
rollback_subnodes:
@@ -3838,6 +3870,7 @@
}
free_smem_areas:
num_smem_areas = 0;
+ kfree(ramdump_segments_tmp);
kfree(smem_areas);
smem_areas = NULL;
return ret;
@@ -3869,6 +3902,7 @@
__func__);
return ret;
}
+ smd_dev = &pdev->dev;
} else if (pdev->dev.platform_data) {
ret = smd_core_platform_init(pdev);
if (ret) {
@@ -3928,6 +3962,26 @@
__func__, notifier->processor,
notifier->name);
+ remote_spin_release(&remote_spinlock, notifier->processor);
+ remote_spin_release_all(notifier->processor);
+
+ if (smem_ramdump_dev) {
+ int ret;
+
+ SMD_INFO("%s: saving ramdump\n", __func__);
+ /*
+ * XPU protection does not currently allow the
+ * auxiliary memory regions to be dumped. If this
+ * changes, then num_smem_areas + 1 should be passed
+ * into do_elf_ramdump() to dump all regions.
+ */
+ ret = do_elf_ramdump(smem_ramdump_dev,
+ smem_ramdump_segments, 1);
+ if (ret < 0)
+ pr_err("%s: unable to dump smem %d\n", __func__,
+ ret);
+ }
+
smd_channel_reset(notifier->processor);
}
@@ -3940,12 +3994,20 @@
void *handle;
struct restart_notifier_block *nb;
+ smem_ramdump_dev = create_ramdump_device("smem-smd", smd_dev);
+ if (IS_ERR_OR_NULL(smem_ramdump_dev)) {
+ pr_err("%s: Unable to create smem ramdump device.\n",
+ __func__);
+ smem_ramdump_dev = NULL;
+ }
+
for (i = 0; i < ARRAY_SIZE(restart_notifiers); i++) {
nb = &restart_notifiers[i];
handle = subsys_notif_register_notifier(nb->name, &nb->nb);
SMD_DBG("%s: registering notif for '%s', handle=%p\n",
__func__, nb->name, handle);
}
+
return 0;
}
late_initcall(modem_restart_late_init);
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index eb7aa8a..7eb9ead 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -645,8 +645,9 @@
struct smd_pkt_dev *smd_pkt_devp = priv;
if (smd_pkt_devp->ch == 0) {
- pr_err("%s on a closed smd_pkt_dev id:%d\n",
- __func__, smd_pkt_devp->i);
+ if (event != SMD_EVENT_CLOSE)
+ pr_err("%s on a closed smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
return;
}
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 29481d3..5fe7a29 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -72,6 +72,11 @@
[SUBSYS_ONLINE] = "ONLINE",
};
+static const char * const restart_levels[] = {
+ [RESET_SOC] = "SYSTEM",
+ [RESET_SUBSYS_COUPLED] = "RELATED",
+};
+
/**
* struct subsys_tracking - track state of a subsystem or restart order
* @p_state: private state of subsystem/order
@@ -123,6 +128,7 @@
* @owner: module that provides @desc
* @count: reference count of subsystem_get()/subsystem_put()
* @id: ida
+ * @restart_level: restart level (0 - panic, 1 - related, 2 - independent, etc.)
* @restart_order: order of other devices this devices restarts with
* @dentry: debugfs directory for this device
* @do_ramdump_on_put: ramdump on subsystem_put() if true
@@ -140,6 +146,7 @@
struct module *owner;
int count;
int id;
+ int restart_level;
struct subsys_soc_restart_order *restart_order;
#ifdef CONFIG_DEBUG_FS
struct dentry *dentry;
@@ -167,6 +174,38 @@
return snprintf(buf, PAGE_SIZE, "%s\n", subsys_states[state]);
}
+static ssize_t
+restart_level_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int level = to_subsys(dev)->restart_level;
+ return snprintf(buf, PAGE_SIZE, "%s\n", restart_levels[level]);
+}
+
+static ssize_t restart_level_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct subsys_device *subsys = to_subsys(dev);
+ int i;
+ const char *p;
+
+ p = memchr(buf, '\n', count);
+ if (p)
+ count = p - buf;
+
+ for (i = 0; i < ARRAY_SIZE(restart_levels); i++)
+ if (!strncasecmp(buf, restart_levels[i], count)) {
+ subsys->restart_level = i;
+ return count;
+ }
+ return -EPERM;
+}
+
+int subsys_get_restart_level(struct subsys_device *dev)
+{
+ return dev->restart_level;
+}
+EXPORT_SYMBOL(subsys_get_restart_level);
+
static void subsys_set_state(struct subsys_device *subsys,
enum subsys_state state)
{
@@ -199,6 +238,7 @@
static struct device_attribute subsys_attrs[] = {
__ATTR_RO(name),
__ATTR_RO(state),
+ __ATTR(restart_level, 0644, restart_level_show, restart_level_store),
__ATTR_NULL,
};
@@ -259,48 +299,6 @@
static struct subsys_soc_restart_order **restart_orders;
static int n_restart_orders;
-static int restart_level = RESET_SOC;
-
-int get_restart_level()
-{
- return restart_level;
-}
-EXPORT_SYMBOL(get_restart_level);
-
-static int restart_level_set(const char *val, struct kernel_param *kp)
-{
- int ret;
- int old_val = restart_level;
-
- if (cpu_is_msm9615()) {
- pr_err("Only Phase 1 subsystem restart is supported\n");
- return -EINVAL;
- }
-
- ret = param_set_int(val, kp);
- if (ret)
- return ret;
-
- switch (restart_level) {
- case RESET_SUBSYS_INDEPENDENT:
- if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
- pr_info("Phase 3 is currently unsupported. Using phase 2 instead.\n");
- restart_level = RESET_SUBSYS_COUPLED;
- }
- case RESET_SUBSYS_COUPLED:
- case RESET_SOC:
- pr_info("Phase %d behavior activated.\n", restart_level);
- break;
- default:
- restart_level = old_val;
- return -EINVAL;
- }
- return 0;
-}
-
-module_param_call(restart_level, restart_level_set, param_get_int,
- &restart_level, 0644);
-
static struct subsys_soc_restart_order *
update_restart_order(struct subsys_device *dev)
{
@@ -484,7 +482,7 @@
{
struct subsys_soc_restart_order *order = subsys->restart_order;
- if (restart_level != RESET_SUBSYS_INDEPENDENT && order)
+ if (order)
return &order->track;
else
return &subsys->track;
@@ -603,7 +601,7 @@
* This is because the subsystem list inside the relevant
* restart order is not being traversed.
*/
- if (restart_level != RESET_SUBSYS_INDEPENDENT && order) {
+ if (order) {
list = order->subsys_ptrs;
count = order->count;
track = &order->track;
@@ -662,7 +660,8 @@
struct subsys_tracking *track;
unsigned long flags;
- pr_debug("Restarting %s [level=%d]!\n", desc->name, restart_level);
+ pr_debug("Restarting %s [level=%s]!\n", desc->name,
+ restart_levels[dev->restart_level]);
track = subsys_get_track(dev);
/*
@@ -708,13 +707,12 @@
return -EBUSY;
}
- pr_info("Restart sequence requested for %s, restart_level = %d.\n",
- name, restart_level);
+ pr_info("Restart sequence requested for %s, restart_level = %s.\n",
+ name, restart_levels[dev->restart_level]);
- switch (restart_level) {
+ switch (dev->restart_level) {
case RESET_SUBSYS_COUPLED:
- case RESET_SUBSYS_INDEPENDENT:
__subsystem_restart_dev(dev);
break;
case RESET_SOC:
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index f410e7f..3144113 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -1082,9 +1082,11 @@
__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
gpt->status_mask = BIT(10);
dgt->status_mask = BIT(2);
- gpt->freq = 32765;
- gpt_hz = 32765;
- sclk_hz = 32765;
+ if (!soc_class_is_apq8064()) {
+ gpt->freq = 32765;
+ gpt_hz = 32765;
+ sclk_hz = 32765;
+ }
if (!soc_class_is_msm8930() && !cpu_is_msm8960ab()) {
gpt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
dgt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 3a8bbc5..ed91480 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -213,8 +213,7 @@
__be32 *prop;
char *name;
- if (strncmp(uname, "region@", 7) != 0 || depth != 2 ||
- !of_get_flat_dt_prop(node, "linux,contiguous-region", NULL))
+ if (!of_get_flat_dt_prop(node, "linux,contiguous-region", NULL))
return 0;
prop = of_get_flat_dt_prop(node, "reg", &len);
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 73fe5d6..0f4d613 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -89,7 +89,7 @@
int n = -1, err = 0;
VERIFY(err, 0 != access_ok(access ? VERIFY_WRITE : VERIFY_READ,
- (void __user *)start, len));
+ (void __user *)start, len));
if (err)
goto bail;
VERIFY(err, 0 != (vma = find_vma(current->mm, start)));
@@ -611,27 +611,28 @@
static int get_dev(struct fastrpc_apps *me, struct fastrpc_device **rdev)
{
struct hlist_head *head;
- struct fastrpc_device *dev = 0;
- struct hlist_node *n;
+ struct fastrpc_device *dev = 0, *devfree = 0;
+ struct hlist_node *pos, *n;
uint32_t h = hash_32(current->tgid, RPC_HASH_BITS);
int err = 0;
spin_lock(&me->hlock);
head = &me->htbl[h];
- hlist_for_each_entry(dev, n, head, hn) {
+ hlist_for_each_entry_safe(dev, pos, n, head, hn) {
if (dev->tgid == current->tgid) {
hlist_del(&dev->hn);
+ devfree = dev;
break;
}
}
spin_unlock(&me->hlock);
- VERIFY(err, dev != 0);
+ VERIFY(err, devfree != 0);
if (err)
goto bail;
- *rdev = dev;
+ *rdev = devfree;
bail:
if (err) {
- free_dev(dev);
+ free_dev(devfree);
err = alloc_dev(rdev);
}
return err;
@@ -756,22 +757,23 @@
struct fastrpc_apps *me = &gfa;
uint32_t h = hash_32(current->tgid, RPC_HASH_BITS);
struct hlist_head *head;
- struct hlist_node *pos;
- struct fastrpc_device *dev;
+ struct hlist_node *pos, *n;
+ struct fastrpc_device *dev, *devfree;
rnext:
- dev = 0;
+ devfree = dev = 0;
spin_lock(&me->hlock);
head = &me->htbl[h];
- hlist_for_each_entry(dev, pos, head, hn) {
+ hlist_for_each_entry_safe(dev, pos, n, head, hn) {
if (dev->tgid == current->tgid) {
hlist_del(&dev->hn);
+ devfree = dev;
break;
}
}
spin_unlock(&me->hlock);
- if (dev) {
- free_dev(dev);
+ if (devfree) {
+ free_dev(devfree);
goto rnext;
}
return;
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index 0afb5a2..86276b7 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -217,7 +217,7 @@
{
struct tmc_etr_bam_data *bamdata = drvdata->bamdata;
- get_bam2bam_connection_info(0, PEER_PERIPHERAL_TO_USB,
+ get_bam2bam_connection_info(usb_bam_get_qdss_idx(0),
&bamdata->dest,
&bamdata->dest_pipe_idx,
&bamdata->src_pipe_idx,
diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c
index 574a06b..af75ddd 100644
--- a/drivers/devfreq/governor_performance.c
+++ b/drivers/devfreq/governor_performance.c
@@ -10,6 +10,7 @@
*/
#include <linux/devfreq.h>
+#include "governor.h"
static int devfreq_performance_func(struct devfreq *df,
unsigned long *freq)
@@ -25,8 +26,14 @@
return 0;
}
+static int performance_init(struct devfreq *devfreq)
+{
+ return update_devfreq(devfreq);
+}
+
const struct devfreq_governor devfreq_performance = {
.name = "performance",
+ .init = performance_init,
.get_target_freq = devfreq_performance_func,
.no_central_polling = true,
};
diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c
index d742d4a..fec0cdb 100644
--- a/drivers/devfreq/governor_powersave.c
+++ b/drivers/devfreq/governor_powersave.c
@@ -10,6 +10,7 @@
*/
#include <linux/devfreq.h>
+#include "governor.h"
static int devfreq_powersave_func(struct devfreq *df,
unsigned long *freq)
@@ -22,8 +23,14 @@
return 0;
}
+static int powersave_init(struct devfreq *devfreq)
+{
+ return update_devfreq(devfreq);
+}
+
const struct devfreq_governor devfreq_powersave = {
.name = "powersave",
+ .init = powersave_init,
.get_target_freq = devfreq_powersave_func,
.no_central_polling = true,
};
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 69d523c..38130db 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -378,8 +378,8 @@
struct msm_vfe_tasklet_queue_cmd
tasklet_queue_cmd[MSM_VFE_TASKLETQ_SIZE];
+ uint32_t vfe_hw_version;
struct msm_vfe_hardware_info *hw_info;
-
struct msm_vfe_axi_shared_data axi_data;
struct msm_vfe_stats_shared_data stats_data;
struct msm_vfe_error_info error_info;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index fc0a8b5..b136125 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -29,6 +29,9 @@
#define CDBG(fmt, args...) do { } while (0)
#endif
+#define VFE40_V1_VERSION 0x10000018
+#define VFE40_V2_VERSION 0x1001001A
+
#define VFE40_BURST_LEN 3
#define VFE40_STATS_BURST_LEN 2
#define VFE40_UB_SIZE 1536
@@ -123,53 +126,99 @@
static void msm_vfe40_init_qos_parms(struct vfe_device *vfe_dev)
{
void __iomem *vfebase = vfe_dev->vfe_base;
- msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_0);
- msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_1);
- msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_2);
- msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_3);
- msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_4);
- msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_5);
- msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_6);
- msm_camera_io_w(0x0002AAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_7);
+ if (vfe_dev->vfe_hw_version == VFE40_V1_VERSION) {
+ msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_0);
+ msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_1);
+ msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_2);
+ msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_3);
+ msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_4);
+ msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_5);
+ msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_6);
+ msm_camera_io_w(0x0002AAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_7);
+ } else if (vfe_dev->vfe_hw_version == VFE40_V2_VERSION) {
+ msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_0);
+ msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_1);
+ msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_2);
+ msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_3);
+ msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_4);
+ msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_5);
+ msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_6);
+ msm_camera_io_w(0x0001AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_7);
+ }
}
-static void msm_vfe40_init_vbif_parms(
- void __iomem *vfe_vbif_base)
+static void msm_vfe40_init_vbif_parms(struct vfe_device *vfe_dev)
{
- msm_camera_io_w(0x1,
- vfe_vbif_base + VFE40_VBIF_CLKON);
- msm_camera_io_w(0x01010101,
- vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
- msm_camera_io_w(0x01010101,
- vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
- msm_camera_io_w(0x10010110,
- vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
- msm_camera_io_w(0x00001010,
- vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
- msm_camera_io_w(0x00001010,
- vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
- msm_camera_io_w(0x00000707,
- vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
- msm_camera_io_w(0x00000707,
- vfe_vbif_base + VFE40_VBIF_OCMEM_OUT_MAX_BURST);
- msm_camera_io_w(0x00000030,
- vfe_vbif_base + VFE40_VBIF_ARB_CTL);
- msm_camera_io_w(0x00000FFF,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
- msm_camera_io_w(0x0FFF0FFF,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
- msm_camera_io_w(0x00000001,
- vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
- msm_camera_io_w(0x22222222,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
- msm_camera_io_w(0x00002222,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
+ void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base;
+ if (vfe_dev->vfe_hw_version == VFE40_V1_VERSION) {
+ msm_camera_io_w(0x1,
+ vfe_vbif_base + VFE40_VBIF_CLKON);
+ msm_camera_io_w(0x01010101,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
+ msm_camera_io_w(0x01010101,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
+ msm_camera_io_w(0x10010110,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
+ msm_camera_io_w(0x00001010,
+ vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
+ msm_camera_io_w(0x00001010,
+ vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
+ msm_camera_io_w(0x00000707,
+ vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
+ msm_camera_io_w(0x00000707,
+ vfe_vbif_base + VFE40_VBIF_OCMEM_OUT_MAX_BURST);
+ msm_camera_io_w(0x00000030,
+ vfe_vbif_base + VFE40_VBIF_ARB_CTL);
+ msm_camera_io_w(0x00000FFF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
+ msm_camera_io_w(0x0FFF0FFF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
+ msm_camera_io_w(0x00000001,
+ vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
+ msm_camera_io_w(0x22222222,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
+ msm_camera_io_w(0x00002222,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
+ } else if (vfe_dev->vfe_hw_version == VFE40_V2_VERSION) {
+ msm_camera_io_w(0x1,
+ vfe_vbif_base + VFE40_VBIF_CLKON);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
+ msm_camera_io_w(0x00000010,
+ vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
+ msm_camera_io_w(0x00000010,
+ vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
+ msm_camera_io_w(0x00000707,
+ vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
+ msm_camera_io_w(0x00000010,
+ vfe_vbif_base + VFE40_VBIF_ARB_CTL);
+ msm_camera_io_w(0x00000FFF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
+ msm_camera_io_w(0x0FFF0FFF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
+ msm_camera_io_w(0x00000003,
+ vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
+ msm_camera_io_w(0x22222222,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
+ msm_camera_io_w(0x00002222,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
+ }
}
static int msm_vfe40_init_hardware(struct vfe_device *vfe_dev)
@@ -254,7 +303,7 @@
static void msm_vfe40_init_hardware_reg(struct vfe_device *vfe_dev)
{
msm_vfe40_init_qos_parms(vfe_dev);
- msm_vfe40_init_vbif_parms(vfe_dev->vfe_vbif_base);
+ msm_vfe40_init_vbif_parms(vfe_dev);
/* CGC_OVERRIDE */
msm_camera_io_w(0x3FFFFFFF, vfe_dev->vfe_base + 0x14);
msm_camera_io_w(0xC001FF7F, vfe_dev->vfe_base + 0x974);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index 5baeb28..f337e27 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -637,6 +637,9 @@
mutex_unlock(&vfe_dev->mutex);
return -EINVAL;
}
+ vfe_dev->vfe_hw_version = msm_camera_io_r(vfe_dev->vfe_base);
+ ISP_DBG("%s: HW Version: 0x%x\n", __func__, vfe_dev->vfe_hw_version);
+
vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev);
for (i = 0; i < vfe_dev->hw_info->num_iommu_ctx; i++)
@@ -649,10 +652,6 @@
sizeof(struct msm_vfe_stats_shared_data));
memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info));
vfe_dev->axi_data.hw_info = vfe_dev->hw_info->axi_hw_info;
-
- ISP_DBG("%s: HW Version: 0x%x\n",
- __func__, msm_camera_io_r(vfe_dev->vfe_base));
-
vfe_dev->vfe_open_cnt++;
vfe_dev->taskletq_idx = 0;
mutex_unlock(&vfe_dev->mutex);
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 41234c3..ca5e646 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -754,6 +754,9 @@
case VIDIOC_MSM_CPP_CFG:
rc = msm_cpp_cfg(cpp_dev, ioctl_ptr);
break;
+ case VIDIOC_MSM_CPP_FLUSH_QUEUE:
+ rc = msm_cpp_send_frame_to_hardware(cpp_dev);
+ break;
case VIDIOC_MSM_CPP_GET_EVENTPAYLOAD: {
struct msm_device_queue *queue = &cpp_dev->eventData_q;
struct msm_queue_cmd *event_qcmd;
diff --git a/drivers/media/platform/msm/dvb/video/mpq_dvb_video.c b/drivers/media/platform/msm/dvb/video/mpq_dvb_video.c
index 46002c3..b9fdc5e 100644
--- a/drivers/media/platform/msm/dvb/video/mpq_dvb_video.c
+++ b/drivers/media/platform/msm/dvb/video/mpq_dvb_video.c
@@ -28,7 +28,7 @@
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
-#include <linux/android_pmem.h>
+
#include <linux/clk.h>
#include <linux/timer.h>
#include <mach/msm_subsystem_map.h>
@@ -43,8 +43,6 @@
#define ERR(x...) pr_err(x)
#define MPQ_VID_DEC_NAME "mpq_vidc_dec"
-static unsigned int vidc_mmu_subsystem[] = {
- MSM_SUBSYSTEM_VIDEO};
static char vid_thread_names[DVB_MPQ_NUM_VIDEO_DEVICES][10] = {
"dvb-vid-0",
@@ -1060,10 +1058,7 @@
{
struct vcd_property_hdr vcd_property_hdr;
struct vcd_property_h264_mv_buffer *vcd_h264_mv_buffer = NULL;
- struct msm_mapped_buffer *mapped_buffer = NULL;
u32 vcd_status = VCD_ERR_FAIL;
- u32 len = 0, flags = 0;
- struct file *file;
int rc = 0;
unsigned long ionflag = 0;
unsigned long buffer_size = 0;
@@ -1084,28 +1079,8 @@
vcd_h264_mv_buffer->offset = mv_data->offset;
if (!vcd_get_ion_status()) {
- if (get_pmem_file(vcd_h264_mv_buffer->pmem_fd,
- (unsigned long *) (&(vcd_h264_mv_buffer->
- physical_addr)),
- (unsigned long *) (&vcd_h264_mv_buffer->
- kernel_virtual_addr),
- (unsigned long *) (&len), &file)) {
- ERR("%s(): get_pmem_file failed\n", __func__);
- return -EIO;
- }
- put_pmem_file(file);
- flags = MSM_SUBSYSTEM_MAP_IOVA;
- mapped_buffer = msm_subsystem_map_buffer(
- (unsigned long)vcd_h264_mv_buffer->physical_addr, len,
- flags, vidc_mmu_subsystem,
- sizeof(vidc_mmu_subsystem)/
- sizeof(unsigned int));
- if (IS_ERR(mapped_buffer)) {
- ERR("buffer map failed");
- return PTR_ERR(mapped_buffer);
- }
- vcd_h264_mv_buffer->client_data = (void *) mapped_buffer;
- vcd_h264_mv_buffer->dev_addr = (u8 *)mapped_buffer->iova[0];
+ pr_err("PMEM not available");
+ return -EINVAL;
} else {
client_ctx->h264_mv_ion_handle = ion_import_dma_buf(
client_ctx->user_ion_client,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index e55c0f1..b71a816 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/jiffies.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <asm/div64.h>
@@ -21,7 +22,7 @@
#include "msm_smem.h"
#include "msm_vidc_debug.h"
-#define HW_RESPONSE_TIMEOUT (5 * 60 * 1000)
+#define HW_RESPONSE_TIMEOUT msecs_to_jiffies(200)
#define IS_ALREADY_IN_STATE(__p, __d) ({\
int __rc = (__p >= __d);\
@@ -313,7 +314,7 @@
enum command_response cmd)
{
int rc = 0;
- rc = wait_for_completion_interruptible_timeout(
+ rc = wait_for_completion_timeout(
&inst->completions[SESSION_MSG_INDEX(cmd)],
msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
if (!rc) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 65542bc..62158b0 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -18,7 +18,7 @@
int msm_vidc_debug = 0x3;
int msm_fw_debug = 0x18;
int msm_fw_debug_mode = 0x1;
-int msm_fw_low_power_mode = 0x1;
+int msm_fw_low_power_mode = 0x0;
struct debug_buffer {
char ptr[MAX_DBG_BUF_SIZE];
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index 88dc4fe..d1948d1 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -1188,6 +1188,13 @@
return 0;
}
+static int q6_hfi_get_stride_scanline(int color_fmt,
+ int width, int height, int *stride, int *scanlines) {
+ *stride = VENUS_Y_STRIDE(color_fmt, width);
+ *scanlines = VENUS_Y_SCANLINES(color_fmt, height);
+ return 0;
+}
+
static void q6_init_hfi_callbacks(struct hfi_device *hdev)
{
hdev->core_init = q6_hfi_core_init;
@@ -1223,6 +1230,7 @@
hdev->load_fw = q6_hfi_load_fw;
hdev->unload_fw = q6_hfi_unload_fw;
hdev->get_fw_info = q6_hfi_get_fw_info;
+ hdev->get_stride_scanline = q6_hfi_get_stride_scanline;
}
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 1b7ecf0..424af64 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -2002,12 +2002,8 @@
dprintk(VIDC_ERR, "Invalid params: %p\n", device);
return;
}
- if (device->clocks_enabled) {
- cl = &device->resources.clock[VCODEC_CLK];
- clk_disable_unprepare(cl->clk);
- }
- for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
+ for (i = 0; i < VCODEC_MAX_CLKS; i++) {
cl = &device->resources.clock[i];
clk_disable_unprepare(cl->clk);
}
@@ -2022,17 +2018,7 @@
dprintk(VIDC_ERR, "Invalid params: %p\n", device);
return -EINVAL;
}
- if (!device->clocks_enabled) {
- cl = &device->resources.clock[VCODEC_CLK];
- rc = clk_prepare_enable(cl->clk);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to enable clocks\n");
- goto fail_clk_enable;
- } else {
- dprintk(VIDC_DBG, "Clock: %s enabled\n", cl->name);
- }
- }
- for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
+ for (i = 0; i < VCODEC_MAX_CLKS; i++) {
cl = &device->resources.clock[i];
rc = clk_prepare_enable(cl->clk);
if (rc) {
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 0d7d98b..c0a4cef 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -4,7 +4,7 @@
* Copyright (C) 2003 Russell King, All Rights Reserved.
* Copyright (C) 2007-2008 Pierre Ossman
* Copyright (C) 2010 Linus Walleij
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -43,6 +43,9 @@
struct mmc_host *host = cls_dev_to_mmc_host(dev);
int ret = 0;
+ if (!mmc_use_core_runtime_pm(host))
+ return 0;
+
ret = mmc_suspend_host(host);
if (ret < 0)
pr_err("%s: %s: suspend host failed: %d\n", mmc_hostname(host),
@@ -56,6 +59,9 @@
struct mmc_host *host = cls_dev_to_mmc_host(dev);
int ret = 0;
+ if (!mmc_use_core_runtime_pm(host))
+ return 0;
+
ret = mmc_resume_host(host);
if (ret < 0) {
pr_err("%s: %s: resume host: failed: ret: %d\n",
@@ -72,6 +78,9 @@
struct mmc_host *host = cls_dev_to_mmc_host(dev);
int ret = 0;
+ if (!mmc_use_core_runtime_pm(host))
+ return 0;
+
if (!pm_runtime_suspended(dev)) {
ret = mmc_suspend_host(host);
if (ret < 0)
@@ -86,6 +95,9 @@
struct mmc_host *host = cls_dev_to_mmc_host(dev);
int ret = 0;
+ if (!mmc_use_core_runtime_pm(host))
+ return 0;
+
if (!pm_runtime_suspended(dev)) {
ret = mmc_resume_host(host);
if (ret < 0)
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index a9a850c..f9ae3c2 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -28,34 +28,8 @@
#include <linux/dma-mapping.h>
#include <mach/msm_smsm.h>
-#define USB_SUMMING_THRESHOLD 512
-#define CONNECTIONS_NUM 8
-
-static struct sps_bam_props usb_props;
-static struct sps_pipe *sps_pipes[CONNECTIONS_NUM][2];
-static struct sps_connect sps_connections[CONNECTIONS_NUM][2];
-static struct sps_mem_buffer data_mem_buf[CONNECTIONS_NUM][2];
-static struct sps_mem_buffer desc_mem_buf[CONNECTIONS_NUM][2];
-static struct platform_device *usb_bam_pdev;
-static struct workqueue_struct *usb_bam_wq;
-static u32 h_bam;
-static spinlock_t usb_bam_lock;
-
-struct usb_bam_event_info {
- struct sps_register_event event;
- int (*callback)(void *);
- void *param;
- struct work_struct event_w;
-};
-
-struct usb_bam_connect_info {
- u8 idx;
- u32 *src_pipe;
- u32 *dst_pipe;
- struct usb_bam_event_info wake_event;
- bool src_enabled;
- bool dst_enabled;
-};
+#define USB_THRESHOLD 512
+#define USB_BAM_MAX_STR_LEN 50
enum usb_bam_sm {
USB_BAM_SM_INIT = 0,
@@ -64,7 +38,7 @@
USB_BAM_SM_UNPLUG_NOTIFIED,
};
-struct usb_bam_peer_handhskae_info {
+struct usb_bam_peer_handshake_info {
enum usb_bam_sm state;
bool client_ready;
bool ack_received;
@@ -72,26 +46,79 @@
struct usb_bam_event_info reset_event;
};
-static struct usb_bam_connect_info usb_bam_connections[CONNECTIONS_NUM];
-static struct usb_bam_pipe_connect ***msm_usb_bam_connections_info;
-static struct usb_bam_pipe_connect *bam_connection_arr;
-void __iomem *qscratch_ram1_reg;
-struct clk *mem_clk;
-struct clk *mem_iface_clk;
-struct usb_bam_peer_handhskae_info peer_handhskae_info;
+struct usb_bam_sps_type {
+ struct sps_bam_props usb_props;
+ struct sps_pipe **sps_pipes;
+ struct sps_connect *sps_connections;
+};
-static int connect_pipe(u8 conn_idx, enum usb_bam_pipe_dir pipe_dir,
- u32 *usb_pipe_idx)
+struct usb_bam_ctx_type {
+ struct usb_bam_sps_type usb_bam_sps;
+ struct platform_device *usb_bam_pdev;
+ struct workqueue_struct *usb_bam_wq;
+ void __iomem *qscratch_ram1_reg;
+ u8 max_connections;
+ struct clk *mem_clk;
+ struct clk *mem_iface_clk;
+ char qdss_core_name[USB_BAM_MAX_STR_LEN];
+ char bam_enabled_list[USB_BAM_MAX_STR_LEN];
+ u32 h_bam[MAX_BAMS];
+};
+
+static char *bam_enable_strings[3] = {
+ [SSUSB_BAM] = "ssusb",
+ [HSUSB_BAM] = "hsusb",
+ [HSIC_BAM] = "hsic",
+};
+
+static spinlock_t usb_bam_lock;
+static struct usb_bam_peer_handshake_info peer_handshake_info;
+static struct usb_bam_pipe_connect *usb_bam_connections;
+static struct usb_bam_ctx_type ctx;
+
+static int get_bam_type_from_core_name(const char *name)
+{
+ if (strnstr(name, bam_enable_strings[SSUSB_BAM],
+ USB_BAM_MAX_STR_LEN) ||
+ strnstr(name, "dwc3", USB_BAM_MAX_STR_LEN))
+ return SSUSB_BAM;
+ else if (strnstr(name, bam_enable_strings[HSIC_BAM],
+ USB_BAM_MAX_STR_LEN))
+ return HSIC_BAM;
+ else if (strnstr(name, bam_enable_strings[HSUSB_BAM],
+ USB_BAM_MAX_STR_LEN) ||
+ strnstr(name, "ci", USB_BAM_MAX_STR_LEN))
+ return HSUSB_BAM;
+
+ pr_err("%s: invalid BAM name(%s)\n", __func__, name);
+ return -EINVAL;
+}
+
+static bool bam_use_private_mem(enum usb_bam bam)
+{
+ int i;
+
+ for (i = 0; i < ctx.max_connections; i++)
+ if (usb_bam_connections[i].bam_type == bam &&
+ usb_bam_connections[i].mem_type == USB_PRIVATE_MEM)
+ return true;
+
+ return false;
+}
+
+static int connect_pipe(u8 idx, u32 *usb_pipe_idx)
{
int ret, ram1_value;
- struct sps_pipe **pipe = &sps_pipes[conn_idx][pipe_dir];
- struct sps_connect *connection =
- &sps_connections[conn_idx][pipe_dir];
+ enum usb_bam bam;
+ struct usb_bam_sps_type usb_bam_sps = ctx.usb_bam_sps;
+ struct sps_pipe **pipe = &(usb_bam_sps.sps_pipes[idx]);
+ struct sps_connect *sps_connection = &usb_bam_sps.sps_connections[idx];
struct msm_usb_bam_platform_data *pdata =
- usb_bam_pdev->dev.platform_data;
- struct usb_bam_pipe_connect *pipe_connection =
- &msm_usb_bam_connections_info
- [pdata->usb_active_bam][conn_idx][pipe_dir];
+ ctx.usb_bam_pdev->dev.platform_data;
+ struct usb_bam_pipe_connect *pipe_connect = &usb_bam_connections[idx];
+ enum usb_bam_pipe_dir dir = pipe_connect->dir;
+ struct sps_mem_buffer *data_buf = &(pipe_connect->data_mem_buf);
+ struct sps_mem_buffer *desc_buf = &(pipe_connect->desc_mem_buf);
*pipe = sps_alloc_endpoint();
if (*pipe == NULL) {
@@ -99,42 +126,42 @@
return -ENOMEM;
}
- ret = sps_get_config(*pipe, connection);
+ ret = sps_get_config(*pipe, sps_connection);
if (ret) {
pr_err("%s: tx get config failed %d\n", __func__, ret);
goto free_sps_endpoint;
}
- ret = sps_phy2h(pipe_connection->src_phy_addr, &(connection->source));
+ ret = sps_phy2h(pipe_connect->src_phy_addr, &(sps_connection->source));
if (ret) {
pr_err("%s: sps_phy2h failed (src BAM) %d\n", __func__, ret);
goto free_sps_endpoint;
}
- connection->src_pipe_index = pipe_connection->src_pipe_index;
- ret = sps_phy2h(pipe_connection->dst_phy_addr,
- &(connection->destination));
+ sps_connection->src_pipe_index = pipe_connect->src_pipe_index;
+ ret = sps_phy2h(pipe_connect->dst_phy_addr,
+ &(sps_connection->destination));
if (ret) {
pr_err("%s: sps_phy2h failed (dst BAM) %d\n", __func__, ret);
goto free_sps_endpoint;
}
- connection->dest_pipe_index = pipe_connection->dst_pipe_index;
+ sps_connection->dest_pipe_index = pipe_connect->dst_pipe_index;
- if (pipe_dir == USB_TO_PEER_PERIPHERAL) {
- connection->mode = SPS_MODE_SRC;
- *usb_pipe_idx = connection->src_pipe_index;
+ if (dir == USB_TO_PEER_PERIPHERAL) {
+ sps_connection->mode = SPS_MODE_SRC;
+ *usb_pipe_idx = pipe_connect->src_pipe_index;
} else {
- connection->mode = SPS_MODE_DEST;
- *usb_pipe_idx = connection->dest_pipe_index;
+ sps_connection->mode = SPS_MODE_DEST;
+ *usb_pipe_idx = pipe_connect->dst_pipe_index;
}
/* If BAM is using dedicated SPS pipe memory, get it */
- if (pipe_connection->mem_type == SPS_PIPE_MEM) {
+ if (pipe_connect->mem_type == SPS_PIPE_MEM) {
pr_debug("%s: USB BAM using SPS pipe memory\n", __func__);
ret = sps_setup_bam2bam_fifo(
- &data_mem_buf[conn_idx][pipe_dir],
- pipe_connection->data_fifo_base_offset,
- pipe_connection->data_fifo_size, 1);
+ data_buf,
+ pipe_connect->data_fifo_base_offset,
+ pipe_connect->data_fifo_size, 1);
if (ret) {
pr_err("%s: data fifo setup failure %d\n", __func__,
ret);
@@ -142,90 +169,84 @@
}
ret = sps_setup_bam2bam_fifo(
- &desc_mem_buf[conn_idx][pipe_dir],
- pipe_connection->desc_fifo_base_offset,
- pipe_connection->desc_fifo_size, 1);
+ desc_buf,
+ pipe_connect->desc_fifo_base_offset,
+ pipe_connect->desc_fifo_size, 1);
if (ret) {
pr_err("%s: desc. fifo setup failure %d\n", __func__,
ret);
goto free_sps_endpoint;
}
- } else if (pipe_connection->mem_type == USB_PRIVATE_MEM) {
+ } else if (pipe_connect->mem_type == USB_PRIVATE_MEM) {
pr_debug("%s: USB BAM using private memory\n", __func__);
- if (IS_ERR(mem_clk) || IS_ERR(mem_iface_clk)) {
+ if (IS_ERR(ctx.mem_clk) || IS_ERR(ctx.mem_iface_clk)) {
pr_err("%s: Failed to enable USB mem_clk\n", __func__);
- ret = IS_ERR(mem_clk);
+ ret = IS_ERR(ctx.mem_clk);
goto free_sps_endpoint;
}
- clk_prepare_enable(mem_clk);
- clk_prepare_enable(mem_iface_clk);
+ clk_prepare_enable(ctx.mem_clk);
+ clk_prepare_enable(ctx.mem_iface_clk);
/*
* Enable USB PRIVATE RAM to be used for BAM FIFOs
* HSUSB: Only RAM13 is used for BAM FIFOs
* SSUSB: RAM11, 12, 13 are used for BAM FIFOs
*/
- if (pdata->usb_active_bam == HSUSB_BAM)
+ bam = pipe_connect->bam_type;
+ if (bam < 0)
+ goto free_sps_endpoint;
+
+ if (bam == HSUSB_BAM)
ram1_value = 0x4;
else
ram1_value = 0x7;
pr_debug("Writing 0x%x to QSCRATCH_RAM1\n", ram1_value);
- writel_relaxed(ram1_value, qscratch_ram1_reg);
+ writel_relaxed(ram1_value, ctx.qscratch_ram1_reg);
- data_mem_buf[conn_idx][pipe_dir].phys_base =
- pipe_connection->data_fifo_base_offset +
+ data_buf->phys_base =
+ pipe_connect->data_fifo_base_offset +
pdata->usb_base_address;
- data_mem_buf[conn_idx][pipe_dir].size =
- pipe_connection->data_fifo_size;
- data_mem_buf[conn_idx][pipe_dir].base =
- ioremap(data_mem_buf[conn_idx][pipe_dir].phys_base,
- data_mem_buf[conn_idx][pipe_dir].size);
- memset(data_mem_buf[conn_idx][pipe_dir].base, 0,
- data_mem_buf[conn_idx][pipe_dir].size);
+ data_buf->size = pipe_connect->data_fifo_size;
+ data_buf->base =
+ ioremap(data_buf->phys_base, data_buf->size);
+ memset(data_buf->base, 0, data_buf->size);
- desc_mem_buf[conn_idx][pipe_dir].phys_base =
- pipe_connection->desc_fifo_base_offset +
+ desc_buf->phys_base =
+ pipe_connect->desc_fifo_base_offset +
pdata->usb_base_address;
- desc_mem_buf[conn_idx][pipe_dir].size =
- pipe_connection->desc_fifo_size;
- desc_mem_buf[conn_idx][pipe_dir].base =
- ioremap(desc_mem_buf[conn_idx][pipe_dir].phys_base,
- desc_mem_buf[conn_idx][pipe_dir].size);
- memset(desc_mem_buf[conn_idx][pipe_dir].base, 0,
- desc_mem_buf[conn_idx][pipe_dir].size);
+ desc_buf->size = pipe_connect->desc_fifo_size;
+ desc_buf->base =
+ ioremap(desc_buf->phys_base, desc_buf->size);
+ memset(desc_buf->base, 0, desc_buf->size);
} else {
pr_debug("%s: USB BAM using system memory\n", __func__);
/* BAM would use system memory, allocate FIFOs */
- data_mem_buf[conn_idx][pipe_dir].size =
- pipe_connection->data_fifo_size;
- data_mem_buf[conn_idx][pipe_dir].base =
- dma_alloc_coherent(&usb_bam_pdev->dev,
- pipe_connection->data_fifo_size,
- &data_mem_buf[conn_idx][pipe_dir].phys_base,
- 0);
- memset(data_mem_buf[conn_idx][pipe_dir].base, 0,
- pipe_connection->data_fifo_size);
+ data_buf->size = pipe_connect->data_fifo_size;
+ data_buf->base =
+ dma_alloc_coherent(&ctx.usb_bam_pdev->dev,
+ pipe_connect->data_fifo_size,
+ &(data_buf->phys_base),
+ 0);
+ memset(data_buf->base, 0, pipe_connect->data_fifo_size);
- desc_mem_buf[conn_idx][pipe_dir].size =
- pipe_connection->desc_fifo_size;
- desc_mem_buf[conn_idx][pipe_dir].base =
- dma_alloc_coherent(&usb_bam_pdev->dev,
- pipe_connection->desc_fifo_size,
- &desc_mem_buf[conn_idx][pipe_dir].phys_base,
- 0);
- memset(desc_mem_buf[conn_idx][pipe_dir].base, 0,
- pipe_connection->desc_fifo_size);
+ desc_buf->size = pipe_connect->desc_fifo_size;
+ desc_buf->base =
+ dma_alloc_coherent(&ctx.usb_bam_pdev->dev,
+ pipe_connect->desc_fifo_size,
+ &(desc_buf->phys_base),
+ 0);
+ memset(desc_buf->base, 0, pipe_connect->desc_fifo_size);
}
- connection->data = data_mem_buf[conn_idx][pipe_dir];
- connection->desc = desc_mem_buf[conn_idx][pipe_dir];
- connection->event_thresh = 16;
- connection->options = SPS_O_AUTO_ENABLE;
+ sps_connection->data = *data_buf;
+ sps_connection->desc = *desc_buf;
+ sps_connection->event_thresh = 16;
+ sps_connection->options = SPS_O_AUTO_ENABLE;
- ret = sps_connect(*pipe, connection);
+ ret = sps_connect(*pipe, sps_connection);
if (ret < 0) {
pr_err("%s: sps_connect failed %d\n", __func__, ret);
goto error;
@@ -239,20 +260,15 @@
return ret;
}
-static int connect_pipe_ipa(
- struct usb_bam_connect_ipa_params *connection_params)
+static int connect_pipe_ipa(u8 idx,
+ struct usb_bam_connect_ipa_params *ipa_params)
{
int ret;
- u8 conn_idx = connection_params->idx;
- enum usb_bam_pipe_dir pipe_dir = connection_params->dir;
- struct sps_pipe **pipe = &sps_pipes[conn_idx][pipe_dir];
- struct sps_connect *connection =
- &sps_connections[conn_idx][pipe_dir];
- struct msm_usb_bam_platform_data *pdata =
- usb_bam_pdev->dev.platform_data;
- struct usb_bam_pipe_connect *pipe_connection =
- &msm_usb_bam_connections_info
- [pdata->usb_active_bam][conn_idx][pipe_dir];
+ struct usb_bam_sps_type usb_bam_sps = ctx.usb_bam_sps;
+ enum usb_bam_pipe_dir dir = ipa_params->dir;
+ struct sps_pipe **pipe = &(usb_bam_sps.sps_pipes[idx]);
+ struct sps_connect *sps_connection = &usb_bam_sps.sps_connections[idx];
+ struct usb_bam_pipe_connect *pipe_connect = &usb_bam_connections[idx];
struct ipa_connect_params ipa_in_params;
struct ipa_sps_params sps_out_params;
@@ -262,12 +278,12 @@
memset(&ipa_in_params, 0, sizeof(ipa_in_params));
memset(&sps_out_params, 0, sizeof(sps_out_params));
- if (pipe_dir == USB_TO_PEER_PERIPHERAL) {
- usb_phy_addr = pipe_connection->src_phy_addr;
- ipa_in_params.client_ep_idx = pipe_connection->src_pipe_index;
+ if (dir == USB_TO_PEER_PERIPHERAL) {
+ usb_phy_addr = pipe_connect->src_phy_addr;
+ ipa_in_params.client_ep_idx = pipe_connect->src_pipe_index;
} else {
- usb_phy_addr = pipe_connection->dst_phy_addr;
- ipa_in_params.client_ep_idx = pipe_connection->dst_pipe_index;
+ usb_phy_addr = pipe_connect->dst_phy_addr;
+ ipa_in_params.client_ep_idx = pipe_connect->dst_pipe_index;
}
/* Get HSUSB / HSIC bam handle */
ret = sps_phy2h(usb_phy_addr, &usb_handle);
@@ -279,46 +295,41 @@
/* IPA input parameters */
ipa_in_params.client_bam_hdl = usb_handle;
- ipa_in_params.desc_fifo_sz = pipe_connection->desc_fifo_size;
- ipa_in_params.data_fifo_sz = pipe_connection->data_fifo_size;
- ipa_in_params.notify = connection_params->notify;
- ipa_in_params.priv = connection_params->priv;
- ipa_in_params.client = connection_params->client;
+ ipa_in_params.desc_fifo_sz = pipe_connect->desc_fifo_size;
+ ipa_in_params.data_fifo_sz = pipe_connect->data_fifo_size;
+ ipa_in_params.notify = ipa_params->notify;
+ ipa_in_params.priv = ipa_params->priv;
+ ipa_in_params.client = ipa_params->client;
/* If BAM is using dedicated SPS pipe memory, get it */
- if (pipe_connection->mem_type == SPS_PIPE_MEM) {
+ if (pipe_connect->mem_type == SPS_PIPE_MEM) {
pr_debug("%s: USB BAM using SPS pipe memory\n", __func__);
ret = sps_setup_bam2bam_fifo(
- &data_mem_buf[conn_idx][pipe_dir],
- pipe_connection->data_fifo_base_offset,
- pipe_connection->data_fifo_size, 1);
+ &pipe_connect->data_mem_buf,
+ pipe_connect->data_fifo_base_offset,
+ pipe_connect->data_fifo_size, 1);
if (ret) {
- pr_err("%s: data fifo setup failure %d\n", __func__,
- ret);
+ pr_err("%s: data fifo setup failure %d\n",
+ __func__, ret);
return ret;
}
ret = sps_setup_bam2bam_fifo(
- &desc_mem_buf[conn_idx][pipe_dir],
- pipe_connection->desc_fifo_base_offset,
- pipe_connection->desc_fifo_size, 1);
+ &pipe_connect->desc_mem_buf,
+ pipe_connect->desc_fifo_base_offset,
+ pipe_connect->desc_fifo_size, 1);
if (ret) {
- pr_err("%s: desc. fifo setup failure %d\n", __func__,
- ret);
+ pr_err("%s: desc. fifo setup failure %d\n",
+ __func__, ret);
return ret;
}
- } else {
- pr_err("%s: unsupported memory type(%d)\n",
- __func__, pipe_connection->mem_type);
- return -EINVAL;
+ ipa_in_params.desc = pipe_connect->desc_mem_buf;
+ ipa_in_params.data = pipe_connect->data_mem_buf;
}
- ipa_in_params.desc = desc_mem_buf[conn_idx][pipe_dir];
- ipa_in_params.data = data_mem_buf[conn_idx][pipe_dir];
-
- memcpy(&ipa_in_params.ipa_ep_cfg, &connection_params->ipa_ep_cfg,
+ memcpy(&ipa_in_params.ipa_ep_cfg, &ipa_params->ipa_ep_cfg,
sizeof(struct ipa_ep_cfg));
ret = ipa_connect(&ipa_in_params, &sps_out_params, &clnt_hdl);
@@ -334,38 +345,48 @@
goto disconnect_ipa;
}
- ret = sps_get_config(*pipe, connection);
+ ret = sps_get_config(*pipe, sps_connection);
if (ret) {
pr_err("%s: tx get config failed %d\n", __func__, ret);
goto free_sps_endpoints;
}
- if (pipe_dir == USB_TO_PEER_PERIPHERAL) {
+ if (dir == USB_TO_PEER_PERIPHERAL) {
/* USB src IPA dest */
- connection->mode = SPS_MODE_SRC;
- connection_params->cons_clnt_hdl = clnt_hdl;
- connection->source = usb_handle;
- connection->destination = sps_out_params.ipa_bam_hdl;
- connection->src_pipe_index = pipe_connection->src_pipe_index;
- connection->dest_pipe_index = sps_out_params.ipa_ep_idx;
- *(connection_params->src_pipe) = connection->src_pipe_index;
+ sps_connection->mode = SPS_MODE_SRC;
+ ipa_params->cons_clnt_hdl = clnt_hdl;
+ sps_connection->source = usb_handle;
+ sps_connection->destination = sps_out_params.ipa_bam_hdl;
+ sps_connection->src_pipe_index = pipe_connect->src_pipe_index;
+ sps_connection->dest_pipe_index = sps_out_params.ipa_ep_idx;
+ *(ipa_params->src_pipe) = sps_connection->src_pipe_index;
+ pipe_connect->dst_pipe_index = sps_out_params.ipa_ep_idx;
+ pr_debug("%s: BAM pipe usb[%x]->ipa[%x] connection\n",
+ __func__,
+ pipe_connect->src_pipe_index,
+ pipe_connect->dst_pipe_index);
} else {
/* IPA src, USB dest */
- connection->mode = SPS_MODE_DEST;
- connection_params->prod_clnt_hdl = clnt_hdl;
- connection->source = sps_out_params.ipa_bam_hdl;
- connection->destination = usb_handle;
- connection->src_pipe_index = sps_out_params.ipa_ep_idx;
- connection->dest_pipe_index = pipe_connection->dst_pipe_index;
- *(connection_params->dst_pipe) = connection->dest_pipe_index;
+ sps_connection->mode = SPS_MODE_DEST;
+ ipa_params->prod_clnt_hdl = clnt_hdl;
+ sps_connection->source = sps_out_params.ipa_bam_hdl;
+ sps_connection->destination = usb_handle;
+ sps_connection->src_pipe_index = sps_out_params.ipa_ep_idx;
+ sps_connection->dest_pipe_index = pipe_connect->dst_pipe_index;
+ *(ipa_params->dst_pipe) = sps_connection->dest_pipe_index;
+ pipe_connect->src_pipe_index = sps_out_params.ipa_ep_idx;
+ pr_debug("%s: BAM pipe ipa[%x]->usb[%x] connection\n",
+ __func__,
+ pipe_connect->src_pipe_index,
+ pipe_connect->dst_pipe_index);
}
- connection->data = sps_out_params.data;
- connection->desc = sps_out_params.desc;
- connection->event_thresh = 16;
- connection->options = SPS_O_AUTO_ENABLE;
+ sps_connection->data = sps_out_params.data;
+ sps_connection->desc = sps_out_params.desc;
+ sps_connection->event_thresh = 16;
+ sps_connection->options = SPS_O_AUTO_ENABLE;
- ret = sps_connect(*pipe, connection);
+ ret = sps_connect(*pipe, sps_connection);
if (ret < 0) {
pr_err("%s: sps_connect failed %d\n", __func__, ret);
goto error;
@@ -382,92 +403,85 @@
return ret;
}
-static int disconnect_pipe(u8 connection_idx, enum usb_bam_pipe_dir pipe_dir)
+static int disconnect_pipe(u8 idx)
{
- struct msm_usb_bam_platform_data *pdata =
- usb_bam_pdev->dev.platform_data;
- struct usb_bam_pipe_connect *pipe_connection =
- &msm_usb_bam_connections_info
- [pdata->usb_active_bam][connection_idx][pipe_dir];
- struct sps_pipe *pipe = sps_pipes[connection_idx][pipe_dir];
- struct sps_connect *connection =
- &sps_connections[connection_idx][pipe_dir];
+ struct usb_bam_pipe_connect *pipe_connect =
+ &usb_bam_connections[idx];
+ struct sps_pipe *pipe = ctx.usb_bam_sps.sps_pipes[idx];
+ struct sps_connect *sps_connection =
+ &ctx.usb_bam_sps.sps_connections[idx];
sps_disconnect(pipe);
sps_free_endpoint(pipe);
- if (pipe_connection->mem_type == SYSTEM_MEM) {
+ if (pipe_connect->mem_type == SYSTEM_MEM) {
pr_debug("%s: Freeing system memory used by PIPE\n", __func__);
- dma_free_coherent(&usb_bam_pdev->dev, connection->data.size,
- connection->data.base, connection->data.phys_base);
- dma_free_coherent(&usb_bam_pdev->dev, connection->desc.size,
- connection->desc.base, connection->desc.phys_base);
- } else if (pipe_connection->mem_type == USB_PRIVATE_MEM) {
+ if (sps_connection->data.phys_base)
+ dma_free_coherent(&ctx.usb_bam_pdev->dev,
+ sps_connection->data.size,
+ sps_connection->data.base,
+ sps_connection->data.phys_base);
+ if (sps_connection->desc.phys_base)
+ dma_free_coherent(&ctx.usb_bam_pdev->dev,
+ sps_connection->desc.size,
+ sps_connection->desc.base,
+ sps_connection->desc.phys_base);
+ } else if (pipe_connect->mem_type == USB_PRIVATE_MEM) {
pr_debug("Freeing USB private memory used by BAM PIPE\n");
- writel_relaxed(0x0, qscratch_ram1_reg);
- iounmap(connection->data.base);
- iounmap(connection->desc.base);
- clk_disable_unprepare(mem_clk);
- clk_disable_unprepare(mem_iface_clk);
+ writel_relaxed(0x0, ctx.qscratch_ram1_reg);
+ iounmap(sps_connection->data.base);
+ iounmap(sps_connection->desc.base);
+ clk_disable_unprepare(ctx.mem_clk);
+ clk_disable_unprepare(ctx.mem_iface_clk);
}
- connection->options &= ~SPS_O_AUTO_ENABLE;
+ sps_connection->options &= ~SPS_O_AUTO_ENABLE;
return 0;
}
-int usb_bam_connect(u8 idx, u32 *src_pipe_idx, u32 *dst_pipe_idx)
+int usb_bam_connect(u8 idx, u32 *bam_pipe_idx)
{
- struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
- struct msm_usb_bam_platform_data *pdata =
- usb_bam_pdev->dev.platform_data;
- int usb_active_bam = pdata->usb_active_bam;
int ret;
+ enum usb_bam bam;
+ struct usb_bam_pipe_connect *pipe_connect = &usb_bam_connections[idx];
+ struct msm_usb_bam_platform_data *pdata;
- if (!usb_bam_pdev) {
+ if (!ctx.usb_bam_pdev) {
pr_err("%s: usb_bam device not found\n", __func__);
return -ENODEV;
}
- if (idx >= CONNECTIONS_NUM) {
- pr_err("%s: Invalid connection index\n",
- __func__);
- return -EINVAL;
- }
+ pdata = ctx.usb_bam_pdev->dev.platform_data;
- if (connection->src_enabled && connection->dst_enabled) {
+ if (pipe_connect->enabled) {
pr_debug("%s: connection %d was already established\n",
__func__, idx);
return 0;
}
- connection->src_pipe = src_pipe_idx;
- connection->dst_pipe = dst_pipe_idx;
- connection->idx = idx;
+
+ if (!bam_pipe_idx) {
+ pr_err("%s: invalid bam_pipe_idx\n", __func__);
+ return -EINVAL;
+ }
+ if (idx < 0 || idx > ctx.max_connections) {
+ pr_err("idx is wrong %d", idx);
+ return -EINVAL;
+ }
+ bam = pipe_connect->bam_type;
+ if (bam < 0)
+ return -EINVAL;
/* Check if BAM requires RESET before connect */
- if (pdata->reset_on_connect[usb_active_bam] == true)
- sps_device_reset(h_bam);
+ if (pdata->reset_on_connect[bam] == true)
+ sps_device_reset(ctx.h_bam[bam]);
- if (src_pipe_idx) {
- /* open USB -> Peripheral pipe */
- ret = connect_pipe(connection->idx, USB_TO_PEER_PERIPHERAL,
- connection->src_pipe);
- if (ret) {
- pr_err("%s: src pipe connection failure\n", __func__);
- return ret;
- }
- connection->src_enabled = 1;
+ ret = connect_pipe(idx, bam_pipe_idx);
+ if (ret) {
+ pr_err("%s: pipe connection[%d] failure\n", __func__, idx);
+ return ret;
}
- if (dst_pipe_idx) {
- /* open Peripheral -> USB pipe */
- ret = connect_pipe(connection->idx, PEER_PERIPHERAL_TO_USB,
- connection->dst_pipe);
- if (ret) {
- pr_err("%s: dst pipe connection failure\n", __func__);
- return ret;
- }
- connection->dst_enabled = 1;
- }
+ pipe_connect->enabled = 1;
return 0;
}
@@ -531,64 +545,65 @@
int usb_bam_connect_ipa(struct usb_bam_connect_ipa_params *ipa_params)
{
- u8 idx = ipa_params->idx;
- struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
+ u8 idx;
+ struct usb_bam_pipe_connect *pipe_connect;
int ret;
- if (idx >= CONNECTIONS_NUM) {
- pr_err("%s: Invalid connection index\n",
+ if (!ipa_params) {
+ pr_err("%s: Invalid ipa params\n",
__func__);
return -EINVAL;
}
- if ((connection->src_enabled &&
- ipa_params->dir == USB_TO_PEER_PERIPHERAL) ||
- (connection->dst_enabled &&
- ipa_params->dir == PEER_PERIPHERAL_TO_USB)) {
+ if (ipa_params->dir == USB_TO_PEER_PERIPHERAL)
+ idx = ipa_params->src_idx;
+ else
+ idx = ipa_params->dst_idx;
+
+ if (idx >= ctx.max_connections) {
+ pr_err("%s: Invalid connection index\n",
+ __func__);
+ return -EINVAL;
+ }
+ pipe_connect = &usb_bam_connections[idx];
+
+ if (pipe_connect->enabled) {
pr_debug("%s: connection %d was already established\n",
__func__, idx);
return 0;
}
- if (ipa_params->dir == USB_TO_PEER_PERIPHERAL)
- connection->src_pipe = ipa_params->src_pipe;
- else
- connection->dst_pipe = ipa_params->dst_pipe;
-
- connection->idx = idx;
-
+ ret = connect_pipe_ipa(idx, ipa_params);
ipa_rm_request_resource(IPA_CLIENT_USB_PROD);
- ret = connect_pipe_ipa(ipa_params);
if (ret) {
pr_err("%s: dst pipe connection failure\n", __func__);
return ret;
}
- if (ipa_params->dir == USB_TO_PEER_PERIPHERAL)
- connection->src_enabled = 1;
- else
- connection->dst_enabled = 1;
+ pipe_connect->enabled = 1;
return 0;
}
+EXPORT_SYMBOL(usb_bam_connect_ipa);
int usb_bam_client_ready(bool ready)
{
spin_lock(&usb_bam_lock);
- if (peer_handhskae_info.client_ready == ready) {
+ if (peer_handshake_info.client_ready == ready) {
pr_debug("%s: client state is already %d\n",
__func__, ready);
spin_unlock(&usb_bam_lock);
return 0;
}
- peer_handhskae_info.client_ready = ready;
+ peer_handshake_info.client_ready = ready;
spin_unlock(&usb_bam_lock);
- if (!queue_work(usb_bam_wq, &peer_handhskae_info.reset_event.event_w)) {
+ if (!queue_work(ctx.usb_bam_wq,
+ &peer_handshake_info.reset_event.event_w)) {
spin_lock(&usb_bam_lock);
- peer_handhskae_info.pending_work++;
+ peer_handshake_info.pending_work++;
spin_unlock(&usb_bam_lock);
}
@@ -608,65 +623,65 @@
struct usb_bam_event_info *wake_event_info =
(struct usb_bam_event_info *)notify->user;
- queue_work(usb_bam_wq, &wake_event_info->event_w);
+ queue_work(ctx.usb_bam_wq, &wake_event_info->event_w);
}
static void usb_bam_sm_work(struct work_struct *w)
{
pr_debug("%s: current state: %d\n", __func__,
- peer_handhskae_info.state);
+ peer_handshake_info.state);
spin_lock(&usb_bam_lock);
- switch (peer_handhskae_info.state) {
+ switch (peer_handshake_info.state) {
case USB_BAM_SM_INIT:
- if (peer_handhskae_info.client_ready) {
+ if (peer_handshake_info.client_ready) {
spin_unlock(&usb_bam_lock);
smsm_change_state(SMSM_APPS_STATE, 0,
SMSM_USB_PLUG_UNPLUG);
spin_lock(&usb_bam_lock);
- peer_handhskae_info.state = USB_BAM_SM_PLUG_NOTIFIED;
+ peer_handshake_info.state = USB_BAM_SM_PLUG_NOTIFIED;
}
break;
case USB_BAM_SM_PLUG_NOTIFIED:
- if (peer_handhskae_info.ack_received) {
- peer_handhskae_info.state = USB_BAM_SM_PLUG_ACKED;
- peer_handhskae_info.ack_received = 0;
+ if (peer_handshake_info.ack_received) {
+ peer_handshake_info.state = USB_BAM_SM_PLUG_ACKED;
+ peer_handshake_info.ack_received = 0;
}
break;
case USB_BAM_SM_PLUG_ACKED:
- if (!peer_handhskae_info.client_ready) {
+ if (!peer_handshake_info.client_ready) {
spin_unlock(&usb_bam_lock);
smsm_change_state(SMSM_APPS_STATE,
SMSM_USB_PLUG_UNPLUG, 0);
spin_lock(&usb_bam_lock);
- peer_handhskae_info.state = USB_BAM_SM_UNPLUG_NOTIFIED;
+ peer_handshake_info.state = USB_BAM_SM_UNPLUG_NOTIFIED;
}
break;
case USB_BAM_SM_UNPLUG_NOTIFIED:
- if (peer_handhskae_info.ack_received) {
+ if (peer_handshake_info.ack_received) {
spin_unlock(&usb_bam_lock);
- peer_handhskae_info.reset_event.
- callback(peer_handhskae_info.reset_event.param);
+ peer_handshake_info.reset_event.
+ callback(peer_handshake_info.reset_event.param);
spin_lock(&usb_bam_lock);
- peer_handhskae_info.state = USB_BAM_SM_INIT;
- peer_handhskae_info.ack_received = 0;
+ peer_handshake_info.state = USB_BAM_SM_INIT;
+ peer_handshake_info.ack_received = 0;
}
break;
}
- if (peer_handhskae_info.pending_work) {
- peer_handhskae_info.pending_work--;
+ if (peer_handshake_info.pending_work) {
+ peer_handshake_info.pending_work--;
spin_unlock(&usb_bam_lock);
- queue_work(usb_bam_wq,
- &peer_handhskae_info.reset_event.event_w);
+ queue_work(ctx.usb_bam_wq,
+ &peer_handshake_info.reset_event.event_w);
spin_lock(&usb_bam_lock);
}
spin_unlock(&usb_bam_lock);
}
-static void usb_bam_ack_toggle_cb(void *priv, uint32_t old_state,
- uint32_t new_state)
+static void usb_bam_ack_toggle_cb(void *priv,
+ uint32_t old_state, uint32_t new_state)
{
static int last_processed_state;
int current_state;
@@ -681,27 +696,35 @@
}
last_processed_state = current_state;
- peer_handhskae_info.ack_received = true;
+ peer_handshake_info.ack_received = true;
spin_unlock(&usb_bam_lock);
- if (!queue_work(usb_bam_wq, &peer_handhskae_info.reset_event.event_w)) {
+ if (!queue_work(ctx.usb_bam_wq,
+ &peer_handshake_info.reset_event.event_w)) {
spin_lock(&usb_bam_lock);
- peer_handhskae_info.pending_work++;
+ peer_handshake_info.pending_work++;
spin_unlock(&usb_bam_lock);
}
}
-int usb_bam_register_wake_cb(u8 idx,
- int (*callback)(void *user), void* param)
+int usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
+ void *param)
{
- struct sps_pipe *pipe = sps_pipes[idx][PEER_PERIPHERAL_TO_USB];
- struct sps_connect *sps_connection =
- &sps_connections[idx][PEER_PERIPHERAL_TO_USB];
- struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
- struct usb_bam_event_info *wake_event_info =
- &connection->wake_event;
+ struct sps_pipe *pipe = ctx.usb_bam_sps.sps_pipes[idx];
+ struct sps_connect *sps_connection;
+ struct usb_bam_pipe_connect *pipe_connect;
+ struct usb_bam_event_info *wake_event_info;
int ret;
+ if (idx < 0 || idx > ctx.max_connections) {
+ pr_err("%s:idx is wrong %d", __func__, idx);
+ return -EINVAL;
+ }
+ pipe = ctx.usb_bam_sps.sps_pipes[idx];
+ sps_connection = &ctx.usb_bam_sps.sps_connections[idx];
+ pipe_connect = &usb_bam_connections[idx];
+ wake_event_info = &pipe_connect->wake_event;
+
wake_event_info->param = param;
wake_event_info->callback = callback;
wake_event_info->event.mode = SPS_TRIGGER_CALLBACK;
@@ -717,7 +740,7 @@
sps_connection->options = callback ?
(SPS_O_AUTO_ENABLE | SPS_O_WAKEUP | SPS_O_WAKEUP_IS_ONESHOT) :
- SPS_O_AUTO_ENABLE;
+ SPS_O_AUTO_ENABLE;
ret = sps_set_config(pipe, sps_connection);
if (ret) {
pr_err("%s: sps_set_config() failed %d\n", __func__, ret);
@@ -727,14 +750,13 @@
return 0;
}
-int usb_bam_register_peer_reset_cb(u8 idx,
- int (*callback)(void *), void *param)
+int usb_bam_register_peer_reset_cb(int (*callback)(void *), void *param)
{
u32 ret = 0;
if (callback) {
- peer_handhskae_info.reset_event.param = param;
- peer_handhskae_info.reset_event.callback = callback;
+ peer_handshake_info.reset_event.param = param;
+ peer_handshake_info.reset_event.callback = callback;
ret = smsm_state_cb_register(SMSM_MODEM_STATE,
SMSM_USB_PLUG_UNPLUG, usb_bam_ack_toggle_cb, NULL);
@@ -748,8 +770,8 @@
SMSM_USB_PLUG_UNPLUG);
}
} else {
- peer_handhskae_info.reset_event.param = NULL;
- peer_handhskae_info.reset_event.callback = NULL;
+ peer_handshake_info.reset_event.param = NULL;
+ peer_handshake_info.reset_event.callback = NULL;
smsm_state_cb_deregister(SMSM_MODEM_STATE,
SMSM_USB_PLUG_UNPLUG, usb_bam_ack_toggle_cb, NULL);
}
@@ -759,126 +781,129 @@
int usb_bam_disconnect_pipe(u8 idx)
{
- struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
+ struct usb_bam_pipe_connect *pipe_connect;
int ret;
- if (idx >= CONNECTIONS_NUM) {
- pr_err("%s: Invalid connection index\n",
- __func__);
- return -EINVAL;
- }
+ pipe_connect = &usb_bam_connections[idx];
- if (!connection->src_enabled && !connection->dst_enabled) {
+ if (!pipe_connect->enabled) {
pr_debug("%s: connection %d isn't enabled\n",
__func__, idx);
return 0;
}
- if (connection->src_enabled) {
- /* close USB -> Peripheral pipe */
- ret = disconnect_pipe(connection->idx, USB_TO_PEER_PERIPHERAL);
- if (ret) {
- pr_err("%s: src pipe connection failure\n", __func__);
- return ret;
- }
- connection->src_enabled = 0;
- }
- if (connection->dst_enabled) {
- /* close Peripheral -> USB pipe */
- ret = disconnect_pipe(connection->idx, PEER_PERIPHERAL_TO_USB);
- if (ret) {
- pr_err("%s: dst pipe connection failure\n", __func__);
- return ret;
- }
- connection->dst_enabled = 0;
+ ret = disconnect_pipe(idx);
+ if (ret) {
+ pr_err("%s: src pipe connection failure\n", __func__);
+ return ret;
}
- connection->src_pipe = 0;
- connection->dst_pipe = 0;
+ pipe_connect->enabled = 0;
return 0;
}
-int usb_bam_disconnect_ipa(u8 idx,
- struct usb_bam_connect_ipa_params *ipa_params)
+int usb_bam_disconnect_ipa(struct usb_bam_connect_ipa_params *ipa_params)
{
- struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
int ret;
+ u8 idx;
+ struct usb_bam_pipe_connect *pipe_connect;
+ struct sps_connect *sps_connection;
- if (!usb_bam_pdev) {
- pr_err("%s: usb_bam device not found\n", __func__);
- return -ENODEV;
- }
-
- if (idx >= CONNECTIONS_NUM) {
- pr_err("%s: Invalid connection index\n",
- __func__);
- return -EINVAL;
- }
-
- /* Currently just calls ipa_disconnect, no sps pipes
- disconenction support */
-
- /* close IPA -> USB pipe */
- if (connection->dst_pipe) {
+ if (ipa_params->prod_clnt_hdl) {
+ /* close USB -> IPA pipe */
+ idx = ipa_params->dst_idx;
ret = ipa_disconnect(ipa_params->prod_clnt_hdl);
if (ret) {
pr_err("%s: dst pipe disconnection failure\n",
__func__);
return ret;
}
+ pipe_connect = &usb_bam_connections[idx];
+ sps_connection = &ctx.usb_bam_sps.sps_connections[idx];
+ sps_connection->data.phys_base = 0;
+ sps_connection->desc.phys_base = 0;
+
+ ret = usb_bam_disconnect_pipe(idx);
+ if (ret) {
+ pr_err("%s: failure to disconnect pipe %d\n",
+ __func__, idx);
+ return ret;
+ }
}
- /* close USB -> IPA pipe */
- if (connection->src_pipe) {
+ if (ipa_params->cons_clnt_hdl) {
+ /* close IPA -> USB pipe */
+ idx = ipa_params->src_idx;
ret = ipa_disconnect(ipa_params->cons_clnt_hdl);
if (ret) {
pr_err("%s: src pipe disconnection failure\n",
__func__);
return ret;
}
+ pipe_connect = &usb_bam_connections[idx];
+ sps_connection = &ctx.usb_bam_sps.sps_connections[idx];
+ sps_connection->data.phys_base = 0;
+ sps_connection->desc.phys_base = 0;
+
+ ret = usb_bam_disconnect_pipe(idx);
+ if (ret) {
+ pr_err("%s: failure to disconnect pipe %d\n",
+ __func__, idx);
+ return ret;
+ }
}
ipa_rm_release_resource(IPA_CLIENT_USB_PROD);
return 0;
-
}
+EXPORT_SYMBOL(usb_bam_disconnect_ipa);
-int usb_bam_reset(void)
+int usb_bam_a2_reset(void)
{
- struct usb_bam_connect_info *connection;
+ struct usb_bam_pipe_connect *pipe_connect;
int i;
int ret = 0, ret_int;
- bool reconnect[CONNECTIONS_NUM];
- u32 *reconnect_src_pipe[CONNECTIONS_NUM];
- u32 *reconnect_dst_pipe[CONNECTIONS_NUM];
+ u8 bam = -1;
+ int reconnect_pipe_idx[ctx.max_connections];
- /* Disconnect all pipes */
- for (i = 0; i < CONNECTIONS_NUM; i++) {
- connection = &usb_bam_connections[i];
- reconnect[i] = connection->src_enabled ||
- connection->dst_enabled;
- reconnect_src_pipe[i] = connection->src_pipe;
- reconnect_dst_pipe[i] = connection->dst_pipe;
+ for (i = 0; i < ctx.max_connections; i++)
+ reconnect_pipe_idx[i] = -1;
- ret_int = usb_bam_disconnect_pipe(i);
- if (ret_int) {
- pr_err("%s: failure to connect pipe %d\n",
- __func__, i);
- ret = ret_int;
- continue;
+ /* Disconnect a2 pipes */
+ for (i = 0; i < ctx.max_connections; i++) {
+ pipe_connect = &usb_bam_connections[i];
+ if (strnstr(pipe_connect->name, "a2", USB_BAM_MAX_STR_LEN) &&
+ pipe_connect->enabled) {
+ if (pipe_connect->dir == USB_TO_PEER_PERIPHERAL)
+ reconnect_pipe_idx[i] =
+ pipe_connect->src_pipe_index;
+ else
+ reconnect_pipe_idx[i] =
+ pipe_connect->dst_pipe_index;
+
+ bam = pipe_connect->bam_type;
+ if (bam < 0) {
+ ret = -EINVAL;
+ continue;
+ }
+ ret_int = usb_bam_disconnect_pipe(i);
+ if (ret_int) {
+ pr_err("%s: failure to connect pipe %d\n",
+ __func__, i);
+ ret = ret_int;
+ continue;
+ }
}
}
-
- /* Reset USB/HSIC BAM */
- if (sps_device_reset(h_bam))
+ /* Reset A2 (USB/HSIC) BAM */
+ if (bam != -1 && sps_device_reset(ctx.h_bam[bam]))
pr_err("%s: BAM reset failed\n", __func__);
- /* Reconnect all pipes */
- for (i = 0; i < CONNECTIONS_NUM; i++) {
- connection = &usb_bam_connections[i];
- if (reconnect[i]) {
- ret_int = usb_bam_connect(i, reconnect_src_pipe[i],
- reconnect_dst_pipe[i]);
+ /* Reconnect A2 pipes */
+ for (i = 0; i < ctx.max_connections; i++) {
+ pipe_connect = &usb_bam_connections[i];
+ if (reconnect_pipe_idx[i] != -1) {
+ ret_int = usb_bam_connect(i, &reconnect_pipe_idx[i]);
if (ret_int) {
pr_err("%s: failure to reconnect pipe %d\n",
__func__, i);
@@ -891,134 +916,23 @@
return ret;
}
-static int update_connections_info(struct device_node *node, int bam,
- int conn_num, int dir, enum usb_pipe_mem_type mem_type)
-{
- u32 rc;
- char *key = NULL;
- uint32_t val = 0;
-
- struct usb_bam_pipe_connect *pipe_connection;
-
- pipe_connection = &msm_usb_bam_connections_info[bam][conn_num][dir];
-
- pipe_connection->mem_type = mem_type;
-
- key = "qcom,src-bam-physical-address";
- rc = of_property_read_u32(node, key, &val);
- if (!rc)
- pipe_connection->src_phy_addr = val;
-
- key = "qcom,src-bam-pipe-index";
- rc = of_property_read_u32(node, key, &val);
- if (!rc)
- pipe_connection->src_pipe_index = val;
-
- key = "qcom,dst-bam-physical-address";
- rc = of_property_read_u32(node, key, &val);
- if (!rc)
- pipe_connection->dst_phy_addr = val;
-
- key = "qcom,dst-bam-pipe-index";
- rc = of_property_read_u32(node, key, &val);
- if (!rc)
- pipe_connection->dst_pipe_index = val;
-
- key = "qcom,data-fifo-offset";
- rc = of_property_read_u32(node, key, &val);
- if (!rc)
- pipe_connection->data_fifo_base_offset = val;
-
- key = "qcom,data-fifo-size";
- rc = of_property_read_u32(node, key, &val);
- if (rc)
- goto err;
- pipe_connection->data_fifo_size = val;
-
- key = "qcom,descriptor-fifo-offset";
- rc = of_property_read_u32(node, key, &val);
- if (!rc)
- pipe_connection->desc_fifo_base_offset = val;
-
- key = "qcom,descriptor-fifo-size";
- rc = of_property_read_u32(node, key, &val);
- if (rc)
- goto err;
- pipe_connection->desc_fifo_size = val;
-
- return 0;
-
-err:
- pr_err("%s: Error in name %s key %s\n", __func__,
- node->full_name, key);
- return -EFAULT;
-}
-
-static int usb_bam_update_conn_array_index(struct platform_device *pdev,
- void *buff, int bam_max, int conn_max, int pipe_dirs)
-{
- int bam_num, conn_num;
- struct usb_bam_pipe_connect *bam_connection_arr = buff;
-
- msm_usb_bam_connections_info = devm_kzalloc(&pdev->dev,
- bam_max * sizeof(struct usb_bam_pipe_connect **),
- GFP_KERNEL);
-
- if (!msm_usb_bam_connections_info)
- return -ENOMEM;
-
- for (bam_num = 0; bam_num < bam_max; bam_num++) {
- msm_usb_bam_connections_info[bam_num] =
- devm_kzalloc(&pdev->dev, conn_max *
- sizeof(struct usb_bam_pipe_connect *),
- GFP_KERNEL);
- if (!msm_usb_bam_connections_info[bam_num])
- return -ENOMEM;
-
- for (conn_num = 0; conn_num < conn_max; conn_num++)
- msm_usb_bam_connections_info[bam_num][conn_num] =
- bam_connection_arr +
- (bam_num * conn_max * pipe_dirs) +
- (conn_num * pipe_dirs);
- }
-
- return 0;
-}
-
static struct msm_usb_bam_platform_data *usb_bam_dt_to_pdata(
struct platform_device *pdev)
{
struct msm_usb_bam_platform_data *pdata;
struct device_node *node = pdev->dev.of_node;
- int conn_num, bam;
- u8 dir;
- u8 ncolumns = 2;
- int bam_amount, rc = 0;
- u32 pipe_entry = 0;
- char *key = NULL;
- enum usb_pipe_mem_type mem_type;
+ int rc = 0;
+ u8 i = 0;
bool reset_bam;
+ enum usb_bam bam;
+ ctx.max_connections = 0;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
pr_err("unable to allocate platform data\n");
return NULL;
}
- rc = of_property_read_u32(node, "qcom,usb-active-bam",
- &pdata->usb_active_bam);
- if (rc) {
- pr_err("Invalid usb active bam property\n");
- return NULL;
- }
-
- rc = of_property_read_u32(node, "qcom,usb-total-bam-num",
- &pdata->total_bam_num);
- if (rc) {
- pr_err("Invalid usb total bam num property\n");
- return NULL;
- }
-
rc = of_property_read_u32(node, "qcom,usb-bam-num-pipes",
&pdata->usb_bam_num_pipes);
if (rc) {
@@ -1032,91 +946,113 @@
pr_debug("%s: Invalid usb base address property\n", __func__);
pdata->ignore_core_reset_ack = of_property_read_bool(node,
- "qcom,ignore-core-reset-ack");
+ "qcom,ignore-core-reset-ack");
pdata->disable_clk_gating = of_property_read_bool(node,
- "qcom,disable-clk-gating");
+ "qcom,disable-clk-gating");
for_each_child_of_node(pdev->dev.of_node, node)
- pipe_entry++;
+ ctx.max_connections++;
- /*
- * we need to know the number of connection, so we will know
- * how much memory to allocate
- */
- conn_num = pipe_entry / 2;
- bam_amount = pdata->total_bam_num;
-
- if (conn_num <= 0 || conn_num >= pdata->usb_bam_num_pipes)
+ if (!ctx.max_connections) {
+ pr_err("%s: error: max_connections is zero\n", __func__);
goto err;
+ }
-
- /* alloc msm_usb_bam_connections_info */
- bam_connection_arr = devm_kzalloc(&pdev->dev, bam_amount *
- conn_num * ncolumns *
+ usb_bam_connections = devm_kzalloc(&pdev->dev, ctx.max_connections *
sizeof(struct usb_bam_pipe_connect), GFP_KERNEL);
- if (!bam_connection_arr)
- goto err;
-
- rc = usb_bam_update_conn_array_index(pdev, bam_connection_arr,
- bam_amount, conn_num, ncolumns);
- if (rc)
- goto err;
+ if (!usb_bam_connections) {
+ pr_err("%s: devm_kzalloc failed(%d)\n", __func__, __LINE__);
+ return NULL;
+ }
/* retrieve device tree parameters */
for_each_child_of_node(pdev->dev.of_node, node) {
- const char *str;
-
- key = "qcom,usb-bam-type";
- rc = of_property_read_u32(node, key, &bam);
+ rc = of_property_read_string(node, "label",
+ &usb_bam_connections[i].name);
if (rc)
goto err;
- key = "qcom,usb-bam-mem-type";
- rc = of_property_read_u32(node, key, &mem_type);
+ rc = of_property_read_u32(node, "qcom,usb-bam-mem-type",
+ &usb_bam_connections[i].mem_type);
if (rc)
goto err;
- if (mem_type == USB_PRIVATE_MEM &&
- !pdata->usb_base_address)
- goto err;
-
- rc = of_property_read_string(node, "label", &str);
- if (rc) {
- pr_err("Cannot read string\n");
+ if (usb_bam_connections[i].mem_type == USB_PRIVATE_MEM &&
+ !pdata->usb_base_address) {
+ pr_err("%s: base address is missing for private mem\n",
+ __func__);
goto err;
}
+
+ rc = of_property_read_u32(node, "qcom,bam-type",
+ &usb_bam_connections[i].bam_type);
+ if (rc) {
+ pr_err("%s: bam type is missing in device tree\n",
+ __func__);
+ goto err;
+ }
+
+ rc = of_property_read_u32(node, "qcom,peer-bam",
+ &usb_bam_connections[i].peer_bam);
+ if (rc) {
+ pr_err("%s: peer bam is missing in device tree\n",
+ __func__);
+ goto err;
+ }
+ rc = of_property_read_u32(node, "qcom,dir",
+ &usb_bam_connections[i].dir);
+ if (rc) {
+ pr_err("%s: direction is missing in device tree\n",
+ __func__);
+ goto err;
+ }
+
+ rc = of_property_read_u32(node, "qcom,pipe-num",
+ &usb_bam_connections[i].pipe_num);
+ if (rc) {
+ pr_err("%s: pipe num is missing in device tree\n",
+ __func__);
+ goto err;
+ }
+
reset_bam = of_property_read_bool(node,
- "qcom,reset-bam-on-connect");
+ "qcom,reset-bam-on-connect");
if (reset_bam)
pdata->reset_on_connect[bam] = true;
- if (strnstr(str, "usb-to", 30))
- dir = USB_TO_PEER_PERIPHERAL;
- else if (strnstr(str, "to-usb", 30))
- dir = PEER_PERIPHERAL_TO_USB;
- else
- goto err;
+ of_property_read_u32(node, "qcom,src-bam-physical-address",
+ &usb_bam_connections[i].src_phy_addr);
- /* Check if connection type is supported */
- if (!strcmp(str, "usb-to-peri-qdss-dwc3") ||
- !strcmp(str, "peri-to-usb-qdss-dwc3") ||
- !strcmp(str, "usb-to-ipa") ||
- !strcmp(str, "ipa-to-usb") ||
- !strcmp(str, "usb-to-peri-qdss-hsusb") ||
- !strcmp(str, "peri-to-usb-qdss-hsusb"))
- conn_num = 0;
- else
- goto err;
+ of_property_read_u32(node, "qcom,src-bam-pipe-index",
+ &usb_bam_connections[i].src_pipe_index);
- rc = update_connections_info(node, bam, conn_num,
- dir, mem_type);
+ of_property_read_u32(node, "qcom,dst-bam-physical-address",
+ &usb_bam_connections[i].dst_phy_addr);
+
+ of_property_read_u32(node, "qcom,dst-bam-pipe-index",
+ &usb_bam_connections[i].dst_pipe_index);
+
+ of_property_read_u32(node, "qcom,data-fifo-offset",
+ &usb_bam_connections[i].data_fifo_base_offset);
+
+ rc = of_property_read_u32(node, "qcom,data-fifo-size",
+ &usb_bam_connections[i].data_fifo_size);
if (rc)
goto err;
+
+ of_property_read_u32(node, "qcom,descriptor-fifo-offset",
+ &usb_bam_connections[i].desc_fifo_base_offset);
+
+ rc = of_property_read_u32(node, "qcom,descriptor-fifo-size",
+ &usb_bam_connections[i].desc_fifo_size);
+ if (rc)
+ goto err;
+ i++;
}
- pdata->connections = &msm_usb_bam_connections_info[0][0][0];
+ pdata->connections = usb_bam_connections;
return pdata;
err:
@@ -1124,83 +1060,78 @@
return NULL;
}
-static char *bam_enable_strings[3] = {
- [SSUSB_BAM] = "ssusb",
- [HSUSB_BAM] = "hsusb",
- [HSIC_BAM] = "hsic",
-};
-
-static int usb_bam_init(void)
+static int usb_bam_init(int bam_idx)
{
- int ret;
+ int ret, irq;
void *usb_virt_addr;
struct msm_usb_bam_platform_data *pdata =
- usb_bam_pdev->dev.platform_data;
- struct usb_bam_pipe_connect *pipe_connection =
- &msm_usb_bam_connections_info[pdata->usb_active_bam][0][0];
+ ctx.usb_bam_pdev->dev.platform_data;
struct resource *res, *ram_resource;
- int irq;
+ struct sps_bam_props props = ctx.usb_bam_sps.usb_props;
- res = platform_get_resource_byname(usb_bam_pdev, IORESOURCE_MEM,
- bam_enable_strings[pdata->usb_active_bam]);
+ pr_debug("%s: usb_bam_init - %s\n", __func__,
+ bam_enable_strings[bam_idx]);
+ res = platform_get_resource_byname(ctx.usb_bam_pdev, IORESOURCE_MEM,
+ bam_enable_strings[bam_idx]);
if (!res) {
- dev_err(&usb_bam_pdev->dev, "Unable to get memory resource\n");
- return -ENODEV;
+ dev_dbg(&ctx.usb_bam_pdev->dev, "bam not initialized\n");
+ return 0;
}
- irq = platform_get_irq_byname(usb_bam_pdev,
- bam_enable_strings[pdata->usb_active_bam]);
+ irq = platform_get_irq_byname(ctx.usb_bam_pdev,
+ bam_enable_strings[bam_idx]);
if (irq < 0) {
- dev_err(&usb_bam_pdev->dev, "Unable to get IRQ resource\n");
+ dev_err(&ctx.usb_bam_pdev->dev, "Unable to get IRQ resource\n");
return irq;
}
- usb_virt_addr = devm_ioremap(&usb_bam_pdev->dev, res->start,
- resource_size(res));
+ usb_virt_addr = devm_ioremap(&ctx.usb_bam_pdev->dev, res->start,
+ resource_size(res));
if (!usb_virt_addr) {
pr_err("%s: ioremap failed\n", __func__);
return -ENOMEM;
}
/* Check if USB3 pipe memory needs to be enabled */
- if (pipe_connection->mem_type == USB_PRIVATE_MEM) {
+ if (bam_idx == SSUSB_BAM && bam_use_private_mem(bam_idx)) {
pr_debug("%s: Enabling USB private memory for: %s\n", __func__,
- bam_enable_strings[pdata->usb_active_bam]);
+ bam_enable_strings[bam_idx]);
- ram_resource = platform_get_resource_byname(usb_bam_pdev,
- IORESOURCE_MEM, "qscratch_ram1_reg");
+ ram_resource = platform_get_resource_byname(ctx.usb_bam_pdev,
+ IORESOURCE_MEM, "qscratch_ram1_reg");
if (!res) {
- dev_err(&usb_bam_pdev->dev, "Unable to get qscratch\n");
+ dev_err(&ctx.usb_bam_pdev->dev, "Unable to get qscratch\n");
ret = -ENODEV;
goto free_bam_regs;
}
- qscratch_ram1_reg = devm_ioremap(&usb_bam_pdev->dev,
- ram_resource->start,
- resource_size(ram_resource));
- if (!qscratch_ram1_reg) {
+ ctx.qscratch_ram1_reg = devm_ioremap(&ctx.usb_bam_pdev->dev,
+ ram_resource->start,
+ resource_size(ram_resource));
+ if (!ctx.qscratch_ram1_reg) {
pr_err("%s: ioremap failed for qscratch\n", __func__);
ret = -ENOMEM;
goto free_bam_regs;
}
}
- usb_props.phys_addr = res->start;
- usb_props.virt_addr = usb_virt_addr;
- usb_props.virt_size = resource_size(res);
- usb_props.irq = irq;
- usb_props.summing_threshold = USB_SUMMING_THRESHOLD;
- usb_props.event_threshold = 512;
- usb_props.num_pipes = pdata->usb_bam_num_pipes;
+ props.phys_addr = res->start;
+ props.virt_addr = usb_virt_addr;
+ props.virt_size = resource_size(res);
+ props.irq = irq;
+ props.summing_threshold = USB_THRESHOLD;
+ props.event_threshold = USB_THRESHOLD;
+ props.num_pipes = pdata->usb_bam_num_pipes;
/*
- * HSUSB and HSIC Cores don't support RESET ACK signal to BAMs
- * Hence, let BAM to ignore acknowledge from USB while resetting PIPE
- */
- if (pdata->ignore_core_reset_ack && pdata->usb_active_bam != SSUSB_BAM)
- usb_props.options = SPS_BAM_NO_EXT_P_RST;
- if (pdata->disable_clk_gating)
- usb_props.options |= SPS_BAM_NO_LOCAL_CLK_GATING;
+ * HSUSB and HSIC Cores don't support RESET ACK signal to BAMs
+ * Hence, let BAM to ignore acknowledge from USB while resetting PIPE
+ */
+ if (pdata->ignore_core_reset_ack && bam_idx != SSUSB_BAM)
+ props.options = SPS_BAM_NO_EXT_P_RST;
- ret = sps_register_bam_device(&usb_props, &h_bam);
+ if (pdata->disable_clk_gating)
+ props.options |= SPS_BAM_NO_LOCAL_CLK_GATING;
+
+ ret = sps_register_bam_device(&props, &(ctx.h_bam[bam_idx]));
if (ret < 0) {
pr_err("%s: register bam error %d\n", __func__, ret);
ret = -EFAULT;
@@ -1210,61 +1141,46 @@
return 0;
free_qscratch_reg:
- iounmap(qscratch_ram1_reg);
+ iounmap(ctx.qscratch_ram1_reg);
free_bam_regs:
iounmap(usb_virt_addr);
return ret;
}
-static ssize_t
-usb_bam_show_enable(struct device *dev, struct device_attribute *attr,
- char *buf)
+static int enable_usb_bams(struct platform_device *pdev)
{
- struct msm_usb_bam_platform_data *pdata = dev->platform_data;
-
- if (!pdata)
- return 0;
- return scnprintf(buf, PAGE_SIZE, "%s\n",
- bam_enable_strings[pdata->usb_active_bam]);
-}
-
-static ssize_t usb_bam_store_enable(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct msm_usb_bam_platform_data *pdata = dev->platform_data;
- char str[10], *pstr;
int ret, i;
- if (!pdata) {
- dev_err(dev, "no usb_bam pdata found\n");
- return -ENODEV;
- }
-
- strlcpy(str, buf, sizeof(str));
- pstr = strim(str);
-
for (i = 0; i < ARRAY_SIZE(bam_enable_strings); i++) {
- if (!strncmp(pstr, bam_enable_strings[i], sizeof(str)))
- pdata->usb_active_bam = i;
+ ret = usb_bam_init(i);
+ if (ret) {
+ pr_err("failed to init usb bam %s\n",
+ bam_enable_strings[i]);
+ return ret;
+ }
}
- dev_dbg(dev, "active_bam=%s\n",
- bam_enable_strings[pdata->usb_active_bam]);
+ ctx.usb_bam_sps.sps_pipes = devm_kzalloc(&pdev->dev,
+ ctx.max_connections * sizeof(struct sps_pipe *),
+ GFP_KERNEL);
- ret = usb_bam_init();
- if (ret) {
- dev_err(dev, "failed to initialize usb bam\n");
- return ret;
+ if (!ctx.usb_bam_sps.sps_pipes) {
+ pr_err("%s: failed to allocate sps_pipes\n", __func__);
+ return -ENOMEM;
}
- return count;
+ ctx.usb_bam_sps.sps_connections = devm_kzalloc(&pdev->dev,
+ ctx.max_connections * sizeof(struct sps_connect),
+ GFP_KERNEL);
+ if (!ctx.usb_bam_sps.sps_connections) {
+ pr_err("%s: failed to allocate sps_connections\n", __func__);
+ return -ENOMEM;
+ }
+
+ return 0;
}
-static DEVICE_ATTR(enable, S_IWUSR | S_IRUSR, usb_bam_show_enable,
- usb_bam_store_enable);
-
static int usb_bam_probe(struct platform_device *pdev)
{
int ret, i;
@@ -1272,89 +1188,126 @@
dev_dbg(&pdev->dev, "usb_bam_probe\n");
- for (i = 0; i < CONNECTIONS_NUM; i++) {
- usb_bam_connections[i].src_enabled = 0;
- usb_bam_connections[i].dst_enabled = 0;
- INIT_WORK(&usb_bam_connections[i].wake_event.event_w,
- usb_bam_work);
- }
+ ctx.mem_clk = devm_clk_get(&pdev->dev, "mem_clk");
+ if (IS_ERR(ctx.mem_clk))
- spin_lock_init(&usb_bam_lock);
- INIT_WORK(&peer_handhskae_info.reset_event.event_w, usb_bam_sm_work);
- mem_clk = devm_clk_get(&pdev->dev, "mem_clk");
- if (IS_ERR(mem_clk))
dev_dbg(&pdev->dev, "failed to get mem_clock\n");
- mem_iface_clk = devm_clk_get(&pdev->dev, "mem_iface_clk");
- if (IS_ERR(mem_iface_clk))
+ ctx.mem_iface_clk = devm_clk_get(&pdev->dev, "mem_iface_clk");
+ if (IS_ERR(ctx.mem_iface_clk))
dev_dbg(&pdev->dev, "failed to get mem_iface_clock\n");
if (pdev->dev.of_node) {
dev_dbg(&pdev->dev, "device tree enabled\n");
pdata = usb_bam_dt_to_pdata(pdev);
if (!pdata)
- return -ENOMEM;
+ return -EINVAL;
pdev->dev.platform_data = pdata;
} else if (!pdev->dev.platform_data) {
dev_err(&pdev->dev, "missing platform_data\n");
return -ENODEV;
} else {
pdata = pdev->dev.platform_data;
- ret = usb_bam_update_conn_array_index(pdev, pdata->connections,
- MAX_BAMS, CONNECTIONS_NUM, 2);
- if (ret) {
- pr_err("usb_bam_update_conn_array_index failed\n");
- return ret;
- }
+ usb_bam_connections = pdata->connections;
+ ctx.max_connections = pdata->max_connections;
}
- usb_bam_pdev = pdev;
+ ctx.usb_bam_pdev = pdev;
- ret = device_create_file(&pdev->dev, &dev_attr_enable);
- if (ret)
- dev_err(&pdev->dev, "failed to create device file\n");
+ for (i = 0; i < ctx.max_connections; i++) {
+ usb_bam_connections[i].enabled = 0;
+ INIT_WORK(&usb_bam_connections[i].wake_event.event_w,
+ usb_bam_work);
+ }
- usb_bam_wq = alloc_workqueue("usb_bam_wq",
+ spin_lock_init(&usb_bam_lock);
+ INIT_WORK(&peer_handshake_info.reset_event.event_w, usb_bam_sm_work);
+
+ ctx.usb_bam_wq = alloc_workqueue("usb_bam_wq",
WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
- if (!usb_bam_wq) {
+ if (!ctx.usb_bam_wq) {
pr_err("unable to create workqueue usb_bam_wq\n");
return -ENOMEM;
}
+ ret = enable_usb_bams(pdev);
+ if (ret) {
+ destroy_workqueue(ctx.usb_bam_wq);
+ return ret;
+ }
usb_bam_ipa_create_resources();
return ret;
}
-void get_bam2bam_connection_info(u8 conn_idx, enum usb_bam_pipe_dir pipe_dir,
- u32 *usb_bam_handle, u32 *usb_bam_pipe_idx, u32 *peer_pipe_idx,
+int usb_bam_get_qdss_idx(u8 num)
+{
+ return usb_bam_get_connection_idx(ctx.qdss_core_name, QDSS_P_BAM,
+ PEER_PERIPHERAL_TO_USB, num);
+}
+EXPORT_SYMBOL(usb_bam_get_qdss_idx);
+
+void usb_bam_set_qdss_core(const char *qdss_core)
+{
+ strlcpy(ctx.qdss_core_name, qdss_core, USB_BAM_MAX_STR_LEN);
+}
+
+int get_bam2bam_connection_info(u8 idx, u32 *usb_bam_handle,
+ u32 *usb_bam_pipe_idx, u32 *peer_pipe_idx,
struct sps_mem_buffer *desc_fifo, struct sps_mem_buffer *data_fifo)
{
- struct sps_connect *connection =
- &sps_connections[conn_idx][pipe_dir];
+ struct usb_bam_pipe_connect *pipe_connect = &usb_bam_connections[idx];
+ enum usb_bam_pipe_dir dir = pipe_connect->dir;
+ struct sps_connect *sps_connection =
+ &ctx.usb_bam_sps.sps_connections[idx];
-
- if (pipe_dir == USB_TO_PEER_PERIPHERAL) {
- *usb_bam_handle = connection->source;
- *usb_bam_pipe_idx = connection->src_pipe_index;
- *peer_pipe_idx = connection->dest_pipe_index;
+ if (dir == USB_TO_PEER_PERIPHERAL) {
+ *usb_bam_handle = sps_connection->source;
+ *usb_bam_pipe_idx = sps_connection->src_pipe_index;
+ *peer_pipe_idx = sps_connection->dest_pipe_index;
} else {
- *usb_bam_handle = connection->destination;
- *usb_bam_pipe_idx = connection->dest_pipe_index;
- *peer_pipe_idx = connection->src_pipe_index;
+ *usb_bam_handle = sps_connection->destination;
+ *usb_bam_pipe_idx = sps_connection->dest_pipe_index;
+ *peer_pipe_idx = sps_connection->src_pipe_index;
}
if (data_fifo)
- memcpy(data_fifo, &data_mem_buf[conn_idx][pipe_dir],
- sizeof(struct sps_mem_buffer));
+ memcpy(data_fifo, &pipe_connect->data_mem_buf,
+ sizeof(struct sps_mem_buffer));
if (desc_fifo)
- memcpy(desc_fifo, &desc_mem_buf[conn_idx][pipe_dir],
- sizeof(struct sps_mem_buffer));
+ memcpy(desc_fifo, &pipe_connect->desc_mem_buf,
+ sizeof(struct sps_mem_buffer));
+ return 0;
}
EXPORT_SYMBOL(get_bam2bam_connection_info);
+
+int usb_bam_get_connection_idx(const char *core_name, enum peer_bam client,
+ enum usb_bam_pipe_dir dir, u32 num)
+{
+ u8 i;
+ int bam_type;
+
+ bam_type = get_bam_type_from_core_name(core_name);
+ if (bam_type < 0)
+ return -EINVAL;
+
+ for (i = 0; i < ctx.max_connections; i++)
+ if (usb_bam_connections[i].bam_type == bam_type &&
+ usb_bam_connections[i].peer_bam == client &&
+ usb_bam_connections[i].dir == dir &&
+ usb_bam_connections[i].pipe_num == num) {
+ pr_debug("%s: index %d was found\n", __func__, i);
+ return i;
+ }
+
+ pr_err("%s: failed for %s\n", __func__, core_name);
+ return -ENODEV;
+}
+EXPORT_SYMBOL(usb_bam_get_connection_idx);
+
static int usb_bam_remove(struct platform_device *pdev)
{
- destroy_workqueue(usb_bam_wq);
+ destroy_workqueue(ctx.usb_bam_wq);
return 0;
}
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 0fdadb9..bc6f289 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -115,8 +115,7 @@
u8 revision1;
u8 revision2;
- int charger_status;
- bool online;
+ int battery_present;
/* platform data */
int r_sense_uohm;
unsigned int v_cutoff_uv;
@@ -149,6 +148,9 @@
int shutdown_soc;
int shutdown_iavg_ma;
+ struct wake_lock low_voltage_wake_lock;
+ bool low_voltage_wake_lock_held;
+ int low_voltage_threshold;
int low_soc_calc_threshold;
int low_soc_calculate_soc_ms;
int calculate_soc_ms;
@@ -204,8 +206,7 @@
};
static enum power_supply_property msm_bms_power_props[] = {
- POWER_SUPPLY_PROP_STATUS,
- POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CURRENT_MAX,
@@ -1141,7 +1142,11 @@
pr_err("vadc read failed with rc: %d\n", rc);
return rc;
}
- *ibat_ua = (int)i_result.result_ua;
+ /*
+ * reverse the current read by the iadc, since the bms uses
+ * flipped battery current polarity.
+ */
+ *ibat_ua = -1 * (int)i_result.result_ua;
*vbat_uv = (int)v_result.physical;
return 0;
@@ -1285,6 +1290,25 @@
return chip->prev_chg_soc;
}
+static void very_low_voltage_check(struct qpnp_bms_chip *chip, int vbat_uv)
+{
+ /*
+ * if battery is very low (v_cutoff voltage + 20mv) hold
+ * a wakelock untill soc = 0%
+ */
+ if (vbat_uv <= chip->low_voltage_threshold
+ && !chip->low_voltage_wake_lock_held) {
+ pr_debug("voltage = %d low holding wakelock\n", vbat_uv);
+ wake_lock(&chip->low_voltage_wake_lock);
+ chip->low_voltage_wake_lock_held = 1;
+ } else if (vbat_uv > chip->low_voltage_threshold
+ && chip->low_voltage_wake_lock_held) {
+ pr_debug("voltage = %d releasing wakelock\n", vbat_uv);
+ chip->low_voltage_wake_lock_held = 0;
+ wake_unlock(&chip->low_voltage_wake_lock);
+ }
+}
+
static int adjust_soc(struct qpnp_bms_chip *chip, struct soc_params *params,
int soc, int batt_temp)
{
@@ -1305,6 +1329,8 @@
goto out;
}
+ very_low_voltage_check(chip, vbat_uv);
+
delta_ocv_uv_limit = DIV_ROUND_CLOSEST(ibat_ua, 1000);
ocv_est_uv = vbat_uv + (ibat_ua * params->rbatt_mohm)/1000;
@@ -1620,7 +1646,8 @@
calculate_soc_delayed_work.work);
int soc = recalculate_soc(chip);
- if (soc < chip->low_soc_calc_threshold)
+ if (soc < chip->low_soc_calc_threshold
+ || chip->low_voltage_wake_lock_held)
schedule_delayed_work(&chip->calculate_soc_delayed_work,
round_jiffies_relative(msecs_to_jiffies
(chip->low_soc_calculate_soc_ms)));
@@ -1838,24 +1865,15 @@
return chip->fcc;
}
-static bool get_prop_bms_online(struct qpnp_bms_chip *chip)
+static int get_prop_bms_present(struct qpnp_bms_chip *chip)
{
- return chip->online;
+ return chip->battery_present;
}
-static int get_prop_bms_status(struct qpnp_bms_chip *chip)
+static void set_prop_bms_present(struct qpnp_bms_chip *chip, int present)
{
- return chip->charger_status;
-}
-
-static void set_prop_bms_online(struct qpnp_bms_chip *chip, bool online)
-{
- chip->online = online;
-}
-
-static void set_prop_bms_status(struct qpnp_bms_chip *chip, int status)
-{
- chip->charger_status = status;
+ if (chip->battery_present != present)
+ chip->battery_present = present;
}
static void qpnp_bms_external_power_changed(struct power_supply *psy)
@@ -1882,11 +1900,8 @@
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
val->intval = get_prop_bms_charge_full_design(chip);
break;
- case POWER_SUPPLY_PROP_STATUS:
- val->intval = get_prop_bms_status(chip);
- break;
- case POWER_SUPPLY_PROP_ONLINE:
- val->intval = get_prop_bms_online(chip);
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = get_prop_bms_present(chip);
break;
default:
return -EINVAL;
@@ -1902,11 +1917,8 @@
bms_psy);
switch (psp) {
- case POWER_SUPPLY_PROP_ONLINE:
- set_prop_bms_online(chip, val->intval);
- break;
- case POWER_SUPPLY_PROP_STATUS:
- set_prop_bms_status(chip, (bool)val->intval);
+ case POWER_SUPPLY_PROP_PRESENT:
+ set_prop_bms_present(chip, val->intval);
break;
default:
return -EINVAL;
@@ -2121,6 +2133,7 @@
"ocv-voltage-high-threshold-uv", rc);
SPMI_PROP_READ(ocv_low_threshold_uv,
"ocv-voltage-low-threshold-uv", rc);
+ SPMI_PROP_READ(low_voltage_threshold, "low-voltage-threshold", rc);
if (chip->adjust_soc_low_threshold >= 45)
chip->adjust_soc_low_threshold = 45;
@@ -2294,6 +2307,7 @@
static int __devinit qpnp_bms_probe(struct spmi_device *spmi)
{
struct qpnp_bms_chip *chip;
+ union power_supply_propval retval = {0,};
int rc, vbatt;
chip = kzalloc(sizeof *chip, GFP_KERNEL);
@@ -2373,6 +2387,8 @@
wake_lock_init(&chip->soc_wake_lock, WAKE_LOCK_SUSPEND,
"qpnp_soc_lock");
+ wake_lock_init(&chip->low_voltage_wake_lock, WAKE_LOCK_SUSPEND,
+ "qpnp_low_voltage_lock");
INIT_DELAYED_WORK(&chip->calculate_soc_delayed_work,
calculate_soc_work);
@@ -2381,6 +2397,14 @@
dev_set_drvdata(&spmi->dev, chip);
device_init_wakeup(&spmi->dev, 1);
+ if (!chip->batt_psy)
+ chip->batt_psy = power_supply_get_by_name("battery");
+ if (chip->batt_psy) {
+ chip->batt_psy->get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_PRESENT, &retval);
+ chip->battery_present = retval.intval;
+ }
+
calculate_soc_work(&(chip->calculate_soc_delayed_work.work));
/* setup & register the battery power supply */
@@ -2417,6 +2441,7 @@
unregister_dc:
wake_lock_destroy(&chip->soc_wake_lock);
+ wake_lock_destroy(&chip->low_voltage_wake_lock);
power_supply_unregister(&chip->bms_psy);
dev_set_drvdata(&spmi->dev, NULL);
error_resource:
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 3d9e4b7..eb0d6d4 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -546,6 +546,9 @@
power_supply_changed(&chip->batt_psy);
}
+ if (chip->bms_psy)
+ power_supply_set_present(chip->bms_psy, batt_present);
+
return IRQ_HANDLED;
}
@@ -1638,6 +1641,7 @@
struct qpnp_chg_chip *chip;
struct resource *resource;
struct spmi_resource *spmi_resource;
+ bool present;
int rc = 0;
chip = kzalloc(sizeof *chip, GFP_KERNEL);
@@ -1936,6 +1940,14 @@
if (rc)
goto fail_chg_enable;
+ /* if bms exists, notify it of the presence of the battery */
+ if (!chip->bms_psy)
+ chip->bms_psy = power_supply_get_by_name("bms");
+ if (chip->bms_psy) {
+ present = get_prop_batt_present(chip);
+ power_supply_set_present(chip->bms_psy, present);
+ }
+
chip->batt_psy.name = "battery";
chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
chip->batt_psy.properties = msm_batt_power_props;
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index b04213c..7d3664a 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -54,6 +54,7 @@
#define TSENS_SW_RST BIT(1)
#define TSENS_ADC_CLK_SEL BIT(2)
#define TSENS_SENSOR0_SHIFT 3
+#define TSENS_62_5_MS_MEAS_PERIOD 1
#define TSENS_312_5_MS_MEAS_PERIOD 2
#define TSENS_MEAS_PERIOD_SHIFT 18
@@ -239,6 +240,7 @@
struct platform_device *pdev;
bool prev_reading_avail;
bool calibration_less_mode;
+ bool tsens_local_init;
int tsens_factor;
uint32_t tsens_num_sensor;
int tsens_irq;
@@ -570,24 +572,28 @@
unsigned int reg_cntl = 0;
unsigned int i;
- reg_cntl = readl_relaxed(TSENS_CTRL_ADDR(tmdev->tsens_addr));
- writel_relaxed(reg_cntl | TSENS_SW_RST,
+ if (tmdev->tsens_local_init) {
+ writel_relaxed(reg_cntl, TSENS_CTRL_ADDR(tmdev->tsens_addr));
+ writel_relaxed(reg_cntl | TSENS_SW_RST,
TSENS_CTRL_ADDR(tmdev->tsens_addr));
- reg_cntl |= ((TSENS_312_5_MS_MEAS_PERIOD << TSENS_MEAS_PERIOD_SHIFT) |
+ reg_cntl |= ((TSENS_62_5_MS_MEAS_PERIOD <<
+ TSENS_MEAS_PERIOD_SHIFT) |
(((1 << tmdev->tsens_num_sensor) - 1) << TSENS_SENSOR0_SHIFT) |
TSENS_EN);
- writel_relaxed(reg_cntl, TSENS_CTRL_ADDR(tmdev->tsens_addr));
- writel_relaxed(TSENS_GLOBAL_INIT_DATA,
+ writel_relaxed(reg_cntl, TSENS_CTRL_ADDR(tmdev->tsens_addr));
+ writel_relaxed(TSENS_GLOBAL_INIT_DATA,
TSENS_GLOBAL_CONFIG(tmdev->tsens_addr));
- writel_relaxed(TSENS_S0_MAIN_CFG_INIT_DATA,
+ writel_relaxed(TSENS_S0_MAIN_CFG_INIT_DATA,
TSENS_S0_MAIN_CONFIG(tmdev->tsens_addr));
- for (i = 0; i < tmdev->tsens_num_sensor; i++) {
- writel_relaxed(TSENS_SN_MIN_MAX_STATUS_CTRL_DATA,
+ for (i = 0; i < tmdev->tsens_num_sensor; i++) {
+ writel_relaxed(TSENS_SN_MIN_MAX_STATUS_CTRL_DATA,
TSENS_SN_MIN_MAX_STATUS_CTRL(tmdev->tsens_addr)
+ (i * TSENS_SN_ADDR_OFFSET));
- writel_relaxed(TSENS_SN_REMOTE_CFG_DATA,
+ writel_relaxed(TSENS_SN_REMOTE_CFG_DATA,
TSENS_SN_REMOTE_CONFIG(tmdev->tsens_addr)
+ (i * TSENS_SN_ADDR_OFFSET));
+ }
+ pr_debug("Local TSENS control initialization\n");
}
writel_relaxed(TSENS_INTERRUPT_EN,
TSENS_UPPER_LOWER_INTERRUPT_CTRL(tmdev->tsens_addr));
@@ -1156,6 +1162,8 @@
tmdev->calibration_less_mode = of_property_read_bool(of_node,
"qcom,calibration-less-mode");
tmdev->calib_mode = calib_type;
+ tmdev->tsens_local_init = of_property_read_bool(of_node,
+ "qcom,tsens_local_init");
tmdev->tsens_irq = platform_get_irq(pdev, 0);
if (tmdev->tsens_irq < 0) {
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 65e4989..63acde1 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -1746,7 +1746,8 @@
if (msm_uport->rx.flush != FLUSH_SHUTDOWN) {
if (msm_uport->rx.flush == FLUSH_NONE) {
msm_hs_stop_rx_locked(uport);
- msm_uport->rx_discard_flush_issued = true;
+ if (!is_blsp_uart(msm_uport))
+ msm_uport->rx_discard_flush_issued = true;
}
spin_unlock_irqrestore(&uport->lock, flags);
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index a32dd15..893f315 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -662,19 +662,30 @@
static int mbim_bam_connect(struct f_mbim *dev)
{
int ret;
+ u8 src_connection_idx, dst_connection_idx;
+ struct usb_gadget *gadget = dev->cdev->gadget;
pr_info("dev:%p portno:%d\n", dev, dev->port_num);
+ src_connection_idx = usb_bam_get_connection_idx(gadget->name, A2_P_BAM,
+ USB_TO_PEER_PERIPHERAL, dev->port_num);
+ dst_connection_idx = usb_bam_get_connection_idx(gadget->name, A2_P_BAM,
+ PEER_PERIPHERAL_TO_USB, dev->port_num);
+ if (src_connection_idx < 0 || dst_connection_idx < 0) {
+ pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
+ return ret;
+ }
+
ret = bam_data_connect(&dev->bam_port, dev->port_num,
- USB_GADGET_XPORT_BAM2BAM, dev->port_num, USB_FUNC_MBIM);
+ USB_GADGET_XPORT_BAM2BAM, src_connection_idx,
+ dst_connection_idx, USB_FUNC_MBIM);
if (ret) {
pr_err("bam_data_setup failed: err:%d\n",
ret);
return ret;
- } else {
- pr_info("mbim bam connected\n");
}
+ pr_info("mbim bam connected\n");
return 0;
}
diff --git a/drivers/usb/gadget/f_qc_ecm.c b/drivers/usb/gadget/f_qc_ecm.c
index 559fd04..51f0e50 100644
--- a/drivers/usb/gadget/f_qc_ecm.c
+++ b/drivers/usb/gadget/f_qc_ecm.c
@@ -390,14 +390,27 @@
static int ecm_qc_bam_connect(struct f_ecm_qc *dev)
{
int ret;
+ u8 src_connection_idx, dst_connection_idx;
+ struct usb_composite_dev *cdev = dev->port.func.config->cdev;
+ struct usb_gadget *gadget = cdev->gadget;
+ enum peer_bam peer_bam = (dev->xport == USB_GADGET_XPORT_BAM2BAM_IPA) ?
+ IPA_P_BAM : A2_P_BAM;
- ecm_qc_bam_port.cdev = dev->port.func.config->cdev;
+ ecm_qc_bam_port.cdev = cdev;
ecm_qc_bam_port.in = dev->port.in_ep;
ecm_qc_bam_port.out = dev->port.out_ep;
/* currently we use the first connection */
+ src_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam,
+ USB_TO_PEER_PERIPHERAL, 0);
+ dst_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam,
+ PEER_PERIPHERAL_TO_USB, 0);
+ if (src_connection_idx < 0 || dst_connection_idx < 0) {
+ pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
+ return ret;
+ }
ret = bam_data_connect(&ecm_qc_bam_port, 0, dev->xport,
- 0, USB_FUNC_ECM);
+ src_connection_idx, dst_connection_idx, USB_FUNC_ECM);
if (ret) {
pr_err("bam_data_connect failed: err:%d\n", ret);
return ret;
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index 51d7bc1..8b01176 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -421,22 +421,33 @@
static int rndis_qc_bam_connect(struct f_rndis_qc *dev)
{
int ret;
+ u8 src_connection_idx, dst_connection_idx;
+ struct usb_composite_dev *cdev = dev->port.func.config->cdev;
+ struct usb_gadget *gadget = cdev->gadget;
- dev->bam_port.cdev = dev->port.func.config->cdev;
+ dev->bam_port.cdev = cdev;
dev->bam_port.in = dev->port.in_ep;
dev->bam_port.out = dev->port.out_ep;
/* currently we use the first connection */
+ src_connection_idx = usb_bam_get_connection_idx(gadget->name, A2_P_BAM,
+ USB_TO_PEER_PERIPHERAL, 0);
+ dst_connection_idx = usb_bam_get_connection_idx(gadget->name, A2_P_BAM,
+ PEER_PERIPHERAL_TO_USB, 0);
+ if (src_connection_idx < 0 || dst_connection_idx < 0) {
+ pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
+ return ret;
+ }
ret = bam_data_connect(&dev->bam_port, 0, USB_GADGET_XPORT_BAM2BAM,
- 0, USB_FUNC_RNDIS);
+ src_connection_idx, dst_connection_idx, USB_FUNC_RNDIS);
if (ret) {
pr_err("bam_data_connect failed: err:%d\n",
ret);
return ret;
- } else {
- pr_info("rndis bam connected\n");
}
+ pr_info("rndis bam connected\n");
+
return 0;
}
diff --git a/drivers/usb/gadget/f_qdss.c b/drivers/usb/gadget/f_qdss.c
index 3069bcb..6518095 100644
--- a/drivers/usb/gadget/f_qdss.c
+++ b/drivers/usb/gadget/f_qdss.c
@@ -1,7 +1,7 @@
/*
* f_qdss.c -- QDSS function Driver
*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -447,8 +447,8 @@
qdss->ch.notify(qdss->ch.priv, USB_QDSS_DISCONNECT, NULL,
NULL);
/* If the app was never started, we can skip USB BAM reset */
- status = set_qdss_data_connection(qdss->data,
- qdss->data->address, 0);
+ status = set_qdss_data_connection(qdss->cdev->gadget,
+ qdss->data, qdss->data->address, 0);
if (status)
pr_err("qdss_disconnect error");
}
@@ -490,7 +490,7 @@
return;
}
- status = set_qdss_data_connection(qdss->data,
+ status = set_qdss_data_connection(qdss->cdev->gadget, qdss->data,
qdss->data->address, 1);
if (status) {
pr_err("set_qdss_data_connection error");
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index af68827..4b9dfbf 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -387,6 +387,8 @@
unsigned port_num;
enum transport_type cxport = rmnet_ports[dev->port_num].ctrl_xport;
enum transport_type dxport = rmnet_ports[dev->port_num].data_xport;
+ u8 src_connection_idx, dst_connection_idx;
+ struct usb_gadget *gadget = dev->cdev->gadget;
pr_debug("%s: ctrl xport: %s data xport: %s dev: %p portno: %d\n",
__func__, xport_to_str(cxport), xport_to_str(dxport),
@@ -435,12 +437,42 @@
}
port_num = rmnet_ports[dev->port_num].data_xport_num;
+
switch (dxport) {
case USB_GADGET_XPORT_BAM:
case USB_GADGET_XPORT_BAM2BAM:
- case USB_GADGET_XPORT_BAM2BAM_IPA:
+ src_connection_idx = usb_bam_get_connection_idx(gadget->name,
+ A2_P_BAM, USB_TO_PEER_PERIPHERAL, port_num);
+ dst_connection_idx = usb_bam_get_connection_idx(gadget->name,
+ A2_P_BAM, PEER_PERIPHERAL_TO_USB, port_num);
+ if (dst_connection_idx < 0 || src_connection_idx < 0) {
+ pr_err("%s: usb_bam_get_connection_idx failed\n",
+ __func__);
+ gsmd_ctrl_disconnect(&dev->port, port_num);
+ return ret;
+ }
ret = gbam_connect(&dev->port, port_num,
- dxport, port_num);
+ dxport, src_connection_idx, dst_connection_idx);
+ if (ret) {
+ pr_err("%s: gbam_connect failed: err:%d\n",
+ __func__, ret);
+ gsmd_ctrl_disconnect(&dev->port, port_num);
+ return ret;
+ }
+ break;
+ case USB_GADGET_XPORT_BAM2BAM_IPA:
+ src_connection_idx = usb_bam_get_connection_idx(gadget->name,
+ IPA_P_BAM, USB_TO_PEER_PERIPHERAL, port_num);
+ dst_connection_idx = usb_bam_get_connection_idx(gadget->name,
+ IPA_P_BAM, PEER_PERIPHERAL_TO_USB, port_num);
+ if (dst_connection_idx < 0 || src_connection_idx < 0) {
+ pr_err("%s: usb_bam_get_connection_idx failed\n",
+ __func__);
+ gsmd_ctrl_disconnect(&dev->port, port_num);
+ return ret;
+ }
+ ret = gbam_connect(&dev->port, port_num,
+ dxport, src_connection_idx, dst_connection_idx);
if (ret) {
pr_err("%s: gbam_connect failed: err:%d\n",
__func__, ret);
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 5a6faf2..3c3fbca 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -100,7 +100,8 @@
u32 src_pipe_idx;
u32 dst_pipe_idx;
- u8 connection_idx;
+ u8 src_connection_idx;
+ u8 dst_connection_idx;
enum transport_type trans;
struct usb_bam_connect_ipa_params ipa_params;
@@ -663,7 +664,7 @@
int ret;
if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
- ret = usb_bam_disconnect_ipa(d->connection_idx, &d->ipa_params);
+ ret = usb_bam_disconnect_ipa(&d->ipa_params);
if (ret)
pr_err("%s: usb_bam_disconnect_ipa failed: err:%d\n",
__func__, ret);
@@ -715,10 +716,15 @@
int ret;
if (d->trans == USB_GADGET_XPORT_BAM2BAM) {
- ret = usb_bam_connect(d->connection_idx, &d->src_pipe_idx,
- &d->dst_pipe_idx);
+ ret = usb_bam_connect(d->src_connection_idx, &d->src_pipe_idx);
if (ret) {
- pr_err("%s: usb_bam_connect failed: err:%d\n",
+ pr_err("%s: usb_bam_connect (src) failed: err:%d\n",
+ __func__, ret);
+ return;
+ }
+ ret = usb_bam_connect(d->dst_connection_idx, &d->dst_pipe_idx);
+ if (ret) {
+ pr_err("%s: usb_bam_connect (dst) failed: err:%d\n",
__func__, ret);
return;
}
@@ -787,8 +793,7 @@
if (d->trans == USB_GADGET_XPORT_BAM2BAM && port->port_num == 0) {
/* Register for peer reset callback */
- usb_bam_register_peer_reset_cb(d->connection_idx,
- gbam_peer_reset_cb, port);
+ usb_bam_register_peer_reset_cb(gbam_peer_reset_cb, port);
ret = usb_bam_client_ready(true);
if (ret) {
@@ -832,7 +837,7 @@
msm_hw_bam_disable(1);
/* Reset BAM */
- ret = usb_bam_reset();
+ ret = usb_bam_a2_reset();
if (ret) {
pr_err("%s: BAM reset failed %d\n", __func__, ret);
goto reenable_eps;
@@ -867,7 +872,7 @@
/* Unregister the peer reset callback */
if (d->trans == USB_GADGET_XPORT_BAM2BAM && port->port_num == 0)
- usb_bam_register_peer_reset_cb(d->connection_idx, NULL, NULL);
+ usb_bam_register_peer_reset_cb(NULL, NULL);
return 0;
}
@@ -1216,7 +1221,8 @@
}
int gbam_connect(struct grmnet *gr, u8 port_num,
- enum transport_type trans, u8 connection_idx)
+ enum transport_type trans, u8 src_connection_idx,
+ u8 dst_connection_idx)
{
struct gbam_port *port;
struct bam_ch_info *d;
@@ -1283,12 +1289,14 @@
if (trans == USB_GADGET_XPORT_BAM2BAM) {
port->gr = gr;
- d->connection_idx = connection_idx;
+ d->src_connection_idx = src_connection_idx;
+ d->dst_connection_idx = dst_connection_idx;
} else if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
port->gr = gr;
d->ipa_params.src_pipe = &(d->src_pipe_idx);
d->ipa_params.dst_pipe = &(d->dst_pipe_idx);
- d->ipa_params.idx = connection_idx;
+ d->ipa_params.src_idx = src_connection_idx;
+ d->ipa_params.dst_idx = dst_connection_idx;
}
d->trans = trans;
@@ -1379,7 +1387,7 @@
pr_debug("%s: suspended port %d\n", __func__, port_num);
- usb_bam_register_wake_cb(d->connection_idx, gbam_wake_cb, port);
+ usb_bam_register_wake_cb(d->dst_connection_idx, gbam_wake_cb, port);
}
void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans)
@@ -1396,5 +1404,5 @@
pr_debug("%s: resumed port %d\n", __func__, port_num);
- usb_bam_register_wake_cb(d->connection_idx, NULL, NULL);
+ usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL);
}
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index 700d07f..83f885a 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -47,7 +47,8 @@
u32 src_pipe_idx;
u32 dst_pipe_idx;
- u8 connection_idx;
+ u8 src_connection_idx;
+ u8 dst_connection_idx;
enum function_type func_type;
enum transport_type trans;
@@ -135,7 +136,7 @@
msm_hw_bam_disable(1);
/* Reset BAM */
- ret = usb_bam_reset();
+ ret = usb_bam_a2_reset();
if (ret) {
pr_err("%s: BAM reset failed %d\n", __func__, ret);
goto reenable_eps;
@@ -169,7 +170,7 @@
}
/* Unregister the peer reset callback */
- usb_bam_register_peer_reset_cb(d->connection_idx, NULL, NULL);
+ usb_bam_register_peer_reset_cb(NULL, NULL);
return 0;
}
@@ -184,7 +185,7 @@
if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
if (d->func_type == USB_FUNC_ECM)
ecm_ipa_disconnect(d->ipa_params.priv);
- ret = usb_bam_disconnect_ipa(d->connection_idx, &d->ipa_params);
+ ret = usb_bam_disconnect_ipa(&d->ipa_params);
if (ret)
pr_err("usb_bam_disconnect_ipa failed: err:%d\n", ret);
}
@@ -237,13 +238,17 @@
}
}
} else { /* transport type is USB_GADGET_XPORT_BAM2BAM */
- ret = usb_bam_connect(d->connection_idx, &d->src_pipe_idx,
- &d->dst_pipe_idx);
- if (ret) {
- pr_err("usb_bam_connect failed: err:%d\n", ret);
- return;
- }
+ ret = usb_bam_connect(d->src_connection_idx, &d->src_pipe_idx);
+ if (ret) {
+ pr_err("usb_bam_connect (src) failed: err:%d\n", ret);
+ return;
}
+ ret = usb_bam_connect(d->dst_connection_idx, &d->dst_pipe_idx);
+ if (ret) {
+ pr_err("usb_bam_connect (dst) failed: err:%d\n", ret);
+ return;
+ }
+}
if (!port->port_usb) {
pr_err("port_usb is NULL");
@@ -282,8 +287,7 @@
/* Register for peer reset callback if USB_GADGET_XPORT_BAM2BAM */
if (d->trans != USB_GADGET_XPORT_BAM2BAM_IPA) {
- usb_bam_register_peer_reset_cb(d->connection_idx,
- bam_data_peer_reset_cb, port);
+ usb_bam_register_peer_reset_cb(bam_data_peer_reset_cb, port);
ret = usb_bam_client_ready(true);
if (ret) {
@@ -369,7 +373,8 @@
}
int bam_data_connect(struct data_port *gr, u8 port_num,
- enum transport_type trans, u8 connection_idx, enum function_type func)
+ enum transport_type trans, u8 src_connection_idx,
+ u8 dst_connection_idx, enum function_type func)
{
struct bam_data_port *port;
struct bam_data_ch_info *d;
@@ -408,14 +413,16 @@
port->port_usb = gr;
- d->connection_idx = connection_idx;
+ d->src_connection_idx = src_connection_idx;
+ d->dst_connection_idx = dst_connection_idx;
d->trans = trans;
if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
d->ipa_params.src_pipe = &(d->src_pipe_idx);
d->ipa_params.dst_pipe = &(d->dst_pipe_idx);
- d->ipa_params.idx = connection_idx;
+ d->ipa_params.src_idx = src_connection_idx;
+ d->ipa_params.dst_idx = dst_connection_idx;
}
d->func_type = func;
@@ -499,7 +506,7 @@
d = &port->data_ch;
pr_debug("%s: suspended port %d\n", __func__, port_num);
- usb_bam_register_wake_cb(d->connection_idx, bam_data_wake_cb, port);
+ usb_bam_register_wake_cb(d->dst_connection_idx, bam_data_wake_cb, port);
}
void bam_data_resume(u8 port_num)
@@ -512,6 +519,6 @@
d = &port->data_ch;
pr_debug("%s: resumed port %d\n", __func__, port_num);
- usb_bam_register_wake_cb(d->connection_idx, NULL, NULL);
+ usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL);
}
diff --git a/drivers/usb/gadget/u_bam_data.h b/drivers/usb/gadget/u_bam_data.h
index 71a01b9..486191b5 100644
--- a/drivers/usb/gadget/u_bam_data.h
+++ b/drivers/usb/gadget/u_bam_data.h
@@ -30,7 +30,8 @@
void bam_data_disconnect(struct data_port *gr, u8 port_num);
int bam_data_connect(struct data_port *gr, u8 port_num,
- enum transport_type trans, u8 connection_idx, enum function_type func);
+ enum transport_type trans, u8 src_connection_idx,
+ u8 dst_connection_idx, enum function_type func);
int bam_data_setup(unsigned int no_bam2bam_port);
diff --git a/drivers/usb/gadget/u_qdss.c b/drivers/usb/gadget/u_qdss.c
index 028d5e6..e241e29 100644
--- a/drivers/usb/gadget/u_qdss.c
+++ b/drivers/usb/gadget/u_qdss.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -15,8 +15,6 @@
#include <linux/usb/msm_hsusb.h>
#include <mach/usb_bam.h>
-#define BAM_CONNC_IDX 0 /* USB bam connection index */
-
struct usb_qdss_bam_connect_info {
u32 usb_bam_pipe_idx;
u32 peer_pipe_idx;
@@ -60,28 +58,33 @@
return 0;
}
-int set_qdss_data_connection(struct usb_ep *data_ep, u8 data_addr, int enable)
+static int set_qdss_data_connection(struct usb_gadget *gadget,
+ struct usb_ep *data_ep, u8 data_addr, int enable)
{
int res = 0;
+ u8 idx;
pr_debug("set_qdss_data_connection\n");
- if (enable) {
- res = usb_bam_connect(BAM_CONNC_IDX, NULL,
- &(bam_info.usb_bam_pipe_idx));
- if (res) {
- pr_err("usb_bam_connection error\n");
- return res;
- }
+ /* There is only one qdss pipe, so the pipe number can be set to 0 */
+ idx = usb_bam_get_connection_idx(gadget->name, QDSS_P_BAM,
+ PEER_PERIPHERAL_TO_USB, 0);
+ if (idx < 0) {
+ pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
+ return idx;
+ }
+ if (enable) {
+ res = usb_bam_connect(idx, &(bam_info.usb_bam_pipe_idx));
bam_info.data_fifo =
kzalloc(sizeof(struct sps_mem_buffer *), GFP_KERNEL);
if (!bam_info.data_fifo) {
pr_err("qdss_data_connection: memory alloc failed\n");
return -ENOMEM;
}
- get_bam2bam_connection_info(BAM_CONNC_IDX,
- PEER_PERIPHERAL_TO_USB, &bam_info.usb_bam_handle,
+ usb_bam_set_qdss_core(gadget->name);
+ get_bam2bam_connection_info(idx,
+ &bam_info.usb_bam_handle,
&bam_info.usb_bam_pipe_idx, &bam_info.peer_pipe_idx,
NULL, bam_info.data_fifo);
@@ -89,13 +92,13 @@
bam_info.data_fifo->size, bam_info.usb_bam_pipe_idx);
} else {
kfree(bam_info.data_fifo);
- res = usb_bam_disconnect_pipe(BAM_CONNC_IDX);
+ res = usb_bam_disconnect_pipe(idx);
if (res) {
pr_err("usb_bam_disconnection error\n");
return res;
}
-
}
+
return res;
}
diff --git a/drivers/usb/gadget/u_rmnet.h b/drivers/usb/gadget/u_rmnet.h
index cea9369..a9cca50 100644
--- a/drivers/usb/gadget/u_rmnet.h
+++ b/drivers/usb/gadget/u_rmnet.h
@@ -48,8 +48,10 @@
int gbam_setup(unsigned int no_bam_port, unsigned int no_bam2bam_port);
int gbam_connect(struct grmnet *gr, u8 port_num,
- enum transport_type trans, u8 connection_idx);
-void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans);
+ enum transport_type trans, u8 src_connection_idx,
+ u8 dst_connection_idx);
+void gbam_disconnect(struct grmnet *gr, u8 port_num,
+ enum transport_type trans);
void gbam_suspend(struct grmnet *gr, u8 port_num, enum transport_type trans);
void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans);
int gsmd_ctrl_connect(struct grmnet *gr, int port_num);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index cdb7048..e8a3795 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -449,6 +449,18 @@
hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) ? 0 : 1;
} /* hdmi_tx_is_dvi_mode */
+static inline void hdmi_tx_send_cable_notification(
+ struct hdmi_tx_ctrl *hdmi_ctrl, int val)
+{
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ if (!hdmi_ctrl->pdata.primary && (hdmi_ctrl->sdev.state != val))
+ switch_set_state(&hdmi_ctrl->sdev, val);
+} /* hdmi_tx_send_cable_notification */
+
static inline void hdmi_tx_set_audio_switch_node(struct hdmi_tx_ctrl *hdmi_ctrl,
int val, bool force)
{
@@ -695,11 +707,11 @@
if (hdmi_ctrl->hpd_state) {
hdmi_tx_read_sink_info(hdmi_ctrl);
- switch_set_state(&hdmi_ctrl->sdev, 1);
+ hdmi_tx_send_cable_notification(hdmi_ctrl, 1);
DEV_INFO("%s: sense cable CONNECTED: state switch to %d\n",
__func__, hdmi_ctrl->sdev.state);
} else {
- switch_set_state(&hdmi_ctrl->sdev, 0);
+ hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
DEV_INFO("%s: sense cable DISCONNECTED: state switch to %d\n",
__func__, hdmi_ctrl->sdev.state);
}
@@ -2097,6 +2109,7 @@
static int hdmi_tx_power_on(struct mdss_panel_data *panel_data)
{
+ u32 timeout;
int rc = 0;
struct dss_io_data *io = NULL;
struct hdmi_tx_ctrl *hdmi_ctrl =
@@ -2121,6 +2134,16 @@
/* If a power down is already underway, wait for it to finish */
flush_work_sync(&hdmi_ctrl->power_off_work);
+ if (hdmi_ctrl->pdata.primary) {
+ timeout = wait_for_completion_interruptible_timeout(
+ &hdmi_ctrl->hpd_done, HZ);
+ if (!timeout) {
+ DEV_ERR("%s: cable connection hasn't happened yet\n",
+ __func__);
+ return -ETIMEDOUT;
+ }
+ }
+
rc = hdmi_tx_set_video_fmt(hdmi_ctrl, &panel_data->panel_info);
if (rc) {
DEV_ERR("%s: cannot set video_fmt.rc=%d\n", __func__, rc);
@@ -2265,7 +2288,7 @@
} else {
hdmi_ctrl->hpd_off_pending = true;
- switch_set_state(&hdmi_ctrl->sdev, 0);
+ hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
DEV_DBG("%s: Hdmi state switch to %d\n", __func__,
hdmi_ctrl->sdev.state);
}
@@ -2441,6 +2464,20 @@
hdmi_tx_sysfs_remove(hdmi_ctrl);
return rc;
}
+
+ if (hdmi_ctrl->pdata.primary) {
+ INIT_COMPLETION(hdmi_ctrl->hpd_done);
+ rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, true);
+ if (rc) {
+ DEV_ERR("%s: hpd_enable failed. rc=%d\n",
+ __func__, rc);
+ hdmi_tx_sysfs_remove(hdmi_ctrl);
+ return rc;
+ } else {
+ hdmi_ctrl->hpd_feature_on = true;
+ }
+ }
+
break;
case MDSS_EVENT_CHECK_PARAMS:
@@ -2487,7 +2524,7 @@
if (!timeout & !hdmi_ctrl->hpd_state) {
DEV_INFO("%s: cable removed during suspend\n",
__func__);
- switch_set_state(&hdmi_ctrl->sdev, 0);
+ hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
rc = -EPERM;
} else {
DEV_DBG("%s: cable present after resume\n",
@@ -3116,6 +3153,13 @@
}
}
+ if (of_find_property(pdev->dev.of_node, "qcom,primary_panel", NULL)) {
+ u32 tmp;
+ of_property_read_u32(pdev->dev.of_node, "qcom,primary_panel",
+ &tmp);
+ pdata->primary = tmp ? true : false;
+ }
+
return rc;
error:
@@ -3175,7 +3219,7 @@
if (rc) {
DEV_ERR("%s: Failed to add child devices. rc=%d\n",
__func__, rc);
- goto failed_init_features;
+ goto failed_reg_panel;
} else {
DEV_DBG("%s: Add child devices.\n", __func__);
}
@@ -3187,8 +3231,6 @@
return rc;
-failed_init_features:
- hdmi_tx_sysfs_remove(hdmi_ctrl);
failed_reg_panel:
hdmi_tx_dev_deinit(hdmi_ctrl);
failed_dev_init:
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 06ae427..8d9a477 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -30,8 +30,9 @@
HDMI_TX_MAX_PM
};
+/* Data filled from device tree */
struct hdmi_tx_platform_data {
- /* Data filled from device tree nodes */
+ bool primary;
struct dss_io_data io[HDMI_TX_MAX_IO];
struct dss_module_power power_data[HDMI_TX_MAX_PM];
};
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index 97428cd..c6b6e3f 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -265,12 +265,12 @@
if (ctx->rot90) {
ctx->opmode |= BIT(5); /* ROT 90 */
swap(ctx->width, ctx->height);
+ ctx->format = mdss_mdp_get_rotator_dst_format(rot->format);
+ } else {
+ ctx->format = rot->format;
}
- if (mdss_mdp_writeback_format_setup(ctx))
- return -EINVAL;
-
- return 0;
+ return mdss_mdp_writeback_format_setup(ctx);
}
static int mdss_mdp_writeback_stop(struct mdss_mdp_ctl *ctl)
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 16369ec..98a8202 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -236,7 +236,7 @@
struct mdss_mdp_format_params *fmt;
struct mdss_mdp_pipe *pipe;
struct mdss_mdp_mixer *mixer = NULL;
- u32 pipe_type, mixer_mux, len;
+ u32 pipe_type, mixer_mux, len, src_format;
int ret;
if (mfd == NULL || mfd->ctl == NULL)
@@ -255,9 +255,13 @@
return -ENOTSUPP;
}
- fmt = mdss_mdp_get_format_params(req->src.format);
+ src_format = req->src.format;
+ if (req->flags & MDP_SOURCE_ROTATED_90)
+ src_format = mdss_mdp_get_rotator_dst_format(src_format);
+
+ fmt = mdss_mdp_get_format_params(src_format);
if (!fmt) {
- pr_err("invalid pipe format %d\n", req->src.format);
+ pr_err("invalid pipe format %d\n", src_format);
return -EINVAL;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.h b/drivers/video/msm/mdss/mdss_mdp_rotator.h
index 70ef6bf..c46f271 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.h
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -42,6 +42,18 @@
struct list_head head;
};
+static inline u32 mdss_mdp_get_rotator_dst_format(u32 in_format)
+{
+ switch (in_format) {
+ case MDP_Y_CBCR_H2V2_VENUS:
+ return MDP_Y_CBCR_H2V2;
+ case MDP_Y_CR_CB_GH2V2:
+ return MDP_Y_CR_CB_H2V2;
+ default:
+ return in_format;
+ }
+}
+
struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_alloc(void);
struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_get(u32 session_id);
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index ea45a8c..79fe16b 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -1,4 +1,4 @@
-/* linux/include/asm-arm/arch-msm/hsusb.h
+/* include/linux/usb/msm_hsusb.h
*
* Copyright (C) 2008 Google, Inc.
* Author: Brian Swetland <swetland@google.com>
@@ -435,68 +435,6 @@
bool core_clk_always_on_workaround;
};
-enum usb_pipe_mem_type {
- SPS_PIPE_MEM = 0, /* Default, SPS dedicated pipe memory */
- USB_PRIVATE_MEM, /* USB's private memory */
- SYSTEM_MEM, /* System RAM, requires allocation */
-};
-
-/**
- * struct usb_bam_pipe_connect: pipe connection information
- * between USB/HSIC BAM and another BAM. USB/HSIC BAM can be
- * either src BAM or dst BAM
- * @src_phy_addr: src bam physical address.
- * @src_pipe_index: src bam pipe index.
- * @dst_phy_addr: dst bam physical address.
- * @dst_pipe_index: dst bam pipe index.
- * @mem_type: type of memory used for BAM FIFOs
- * @data_fifo_base_offset: data fifo offset.
- * @data_fifo_size: data fifo size.
- * @desc_fifo_base_offset: descriptor fifo offset.
- * @desc_fifo_size: descriptor fifo size.
- */
-struct usb_bam_pipe_connect {
- u32 src_phy_addr;
- u32 src_pipe_index;
- u32 dst_phy_addr;
- u32 dst_pipe_index;
- enum usb_pipe_mem_type mem_type;
- u32 data_fifo_base_offset;
- u32 data_fifo_size;
- u32 desc_fifo_base_offset;
- u32 desc_fifo_size;
-};
-
-enum usb_bam {
- SSUSB_BAM = 0,
- HSUSB_BAM,
- HSIC_BAM,
- MAX_BAMS,
-};
-
-/**
- * struct msm_usb_bam_platform_data: pipe connection information
- * between USB/HSIC BAM and another BAM. USB/HSIC BAM can be
- * either src BAM or dst BAM
- * @connections: holds all pipe connections data.
- * @usb_active_bam: set USB or HSIC as the active BAM.
- * @usb_bam_num_pipes: max number of pipes to use.
- * @active_conn_num: number of active pipe connections.
- * @usb_base_address: BAM physical address.
- * @ignore_core_reset_ack: BAM can ignore ACK from USB core during PIPE RESET
- * @disable_clk_gating: Disable clock gating
- */
-struct msm_usb_bam_platform_data {
- struct usb_bam_pipe_connect *connections;
- int usb_active_bam;
- int usb_bam_num_pipes;
- u32 total_bam_num;
- u32 usb_base_address;
- bool ignore_core_reset_ack;
- bool reset_on_connect[MAX_BAMS];
- bool disable_clk_gating;
-};
-
/**
* struct usb_ext_notification: event notification structure
* @notify: pointer to client function to call when ID event is detected.
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index 56c257d..6f8e865 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -109,6 +109,9 @@
#define VIDIOC_MSM_CPP_GET_HW_INFO \
_IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct msm_camera_v4l2_ioctl_t)
+#define VIDIOC_MSM_CPP_FLUSH_QUEUE \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct msm_camera_v4l2_ioctl_t)
+
#define V4L2_EVENT_CPP_FRAME_DONE (V4L2_EVENT_PRIVATE_START + 0)
struct msm_camera_v4l2_ioctl_t {
diff --git a/include/sound/Kbuild b/include/sound/Kbuild
index ba75dca..edadaa9 100644
--- a/include/sound/Kbuild
+++ b/include/sound/Kbuild
@@ -11,3 +11,4 @@
header-y += tlv.h
header-y += compress_params.h
header-y += compress_offload.h
+header-y += lsm_params.h
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index bc68c24..f88c817 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -658,6 +658,11 @@
#define SLIMBUS_3_TX 0x4007
#define SLIMBUS_4_RX 0x4008
#define SLIMBUS_4_TX 0x4009 /* index = 24 */
+#define SLIMBUS_5_RX 0x400a
+#define SLIMBUS_5_TX 0x400b
+#define SLIMBUS_6_RX 0x400c
+#define SLIMBUS_6_TX 0x400d
+#define SLIMBUS_PORT_LAST SLIMBUS_6_TX
#define INT_BT_SCO_RX 0x3000 /* index = 25 */
#define INT_BT_SCO_TX 0x3001 /* index = 26 */
#define INT_BT_A2DP_RX 0x3002 /* index = 27 */
@@ -798,6 +803,15 @@
#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_RX 0x4008
/* SLIMbus Tx port on channel 4. */
#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX 0x4009
+/* SLIMbus Rx port on channel 5. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_RX 0x400a
+/* SLIMbus Tx port on channel 5. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX 0x400b
+/* SLIMbus Rx port on channel 6. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_RX 0x400c
+/* SLIMbus Tx port on channel 6. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_TX 0x400d
+
/* Generic pseudoport 1. */
#define AFE_PORT_ID_PSEUDOPORT_01 0x8001
/* Generic pseudoport 2. */
@@ -1972,7 +1986,6 @@
*/
} __packed;
-
union afe_port_config {
struct afe_param_id_pcm_cfg pcm;
struct afe_param_id_i2s_cfg i2s;
@@ -6442,6 +6455,56 @@
} __packed;
/* SRS TruMedia end */
+/* LSM Specific */
+#define VW_FEAT_DIM (39)
+
+#define APRV2_IDS_SERVICE_ID_ADSP_LSM_V (0xD)
+#define APRV2_IDS_DOMAIN_ID_ADSP_V (0x4)
+#define APRV2_IDS_DOMAIN_ID_APPS_V (0x5)
+
+#define LSM_SESSION_CMD_SHARED_MEM_MAP_REGIONS (0x00012A7F)
+#define LSM_SESSION_CMDRSP_SHARED_MEM_MAP_REGIONS (0x00012A80)
+#define LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS (0x00012A81)
+#define LSM_SESSION_CMD_OPEN_TX (0x00012A82)
+#define LSM_SESSION_CMD_CLOSE_TX (0x00012A88)
+#define LSM_SESSION_CMD_SET_PARAMS (0x00012A83)
+#define LSM_SESSION_CMD_REGISTER_SOUND_MODEL (0x00012A84)
+#define LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL (0x00012A85)
+#define LSM_SESSION_CMD_START (0x00012A86)
+#define LSM_SESSION_CMD_STOP (0x00012A87)
+
+#define LSM_SESSION_EVENT_DETECTION_STATUS (0x00012B00)
+
+#define LSM_MODULE_ID_VOICE_WAKEUP (0x00012C00)
+#define LSM_PARAM_ID_ENDPOINT_DETECT_THRESHOLD (0x00012C01)
+#define LSM_PARAM_ID_OPERATION_MODE (0x00012C02)
+#define LSM_PARAM_ID_GAIN (0x00012C03)
+#define LSM_PARAM_ID_CONNECT_TO_PORT (0x00012C04)
+#define LSM_PARAM_ID_KEYWORD_DETECT_SENSITIVITY (0x00012C05)
+#define LSM_PARAM_ID_USER_DETECT_SENSITIVITY (0x00012C06)
+#define LSM_PARAM_ID_FEATURE_COMPENSATION_DATA (0x00012C07)
+
+
+/* HW MAD specific */
+#define AFE_MODULE_HW_MAD (0x00010230)
+#define AFE_PARAM_ID_HW_MAD_CFG (0x00010231)
+#define AFE_PARAM_ID_HW_MAD_CTRL (0x00010232)
+#define AFE_PARAM_ID_SLIMBUS_SLAVE_PORT_CFG (0x00010233)
+
+/* SW MAD specific */
+#define AFE_MODULE_SW_MAD (0x0001022D)
+#define AFE_PARAM_ID_SW_MAD_CFG (0x0001022E)
+#define AFE_PARAM_ID_SVM_MODEL (0x0001022F)
+
+/* Commands/Params to pass the codec/slimbus data to DSP */
+#define AFE_SVC_CMD_SET_PARAM (0x000100f3)
+#define AFE_MODULE_CDC_DEV_CFG (0x00010234)
+#define AFE_PARAM_ID_CDC_SLIMBUS_SLAVE_CFG (0x00010235)
+#define AFE_PARAM_ID_CDC_REG_CFG (0x00010236)
+#define AFE_PARAM_ID_CDC_REG_CFG_INIT (0x00010237)
+
+#define AFE_MAX_CDC_REGISTERS_TO_CONFIG (20)
+
/* ERROR CODES */
/* Success. The operation completed with no errors. */
#define ADSP_EOK 0x00000000
@@ -6669,4 +6732,104 @@
uint16_t reserved;
} __packed;
+enum afe_config_type {
+ AFE_SLIMBUS_SLAVE_PORT_CONFIG,
+ AFE_SLIMBUS_SLAVE_CONFIG,
+ AFE_CDC_REGISTERS_CONFIG,
+ AFE_MAX_CONFIG_TYPES,
+};
+
+struct afe_param_slimbus_slave_port_cfg {
+ uint32_t minor_version;
+ uint16_t slimbus_dev_id;
+ uint16_t slave_dev_pgd_la;
+ uint16_t slave_dev_intfdev_la;
+ uint16_t bit_width;
+ uint16_t data_format;
+ uint16_t num_channels;
+ uint16_t slave_port_mapping[AFE_PORT_MAX_AUDIO_CHAN_CNT];
+} __packed;
+
+struct afe_param_cdc_slimbus_slave_cfg {
+ uint32_t minor_version;
+ uint32_t device_enum_addr_lsw;
+ uint32_t device_enum_addr_msw;
+ uint16_t tx_slave_port_offset;
+ uint16_t rx_slave_port_offset;
+} __packed;
+
+struct afe_param_cdc_reg_cfg {
+ uint32_t minor_version;
+ uint32_t reg_logical_addr;
+ uint32_t reg_field_type;
+ uint32_t reg_field_bit_mask;
+ uint16_t reg_bit_width;
+ uint16_t reg_offset_scale;
+} __packed;
+
+struct afe_param_cdc_reg_cfg_data {
+ uint32_t num_registers;
+ struct afe_param_cdc_reg_cfg *reg_data;
+} __packed;
+
+struct afe_svc_cmd_set_param {
+ uint32_t payload_size;
+ uint32_t payload_address_lsw;
+ uint32_t payload_address_msw;
+ uint32_t mem_map_handle;
+} __packed;
+
+struct afe_param_hw_mad_ctrl {
+ uint32_t minor_version;
+ uint16_t mad_type;
+ uint16_t mad_enable;
+} __packed;
+
+struct afe_cmd_hw_mad_ctrl {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_hw_mad_ctrl payload;
+} __packed;
+
+struct afe_cmd_hw_mad_slimbus_slave_port_cfg {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_slimbus_slave_port_cfg sb_port_cfg;
+} __packed;
+
+struct afe_cmd_sw_mad_enable {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+} __packed;
+
+struct afe_param_cdc_reg_cfg_payload {
+ struct afe_port_param_data_v2 common;
+ struct afe_param_cdc_reg_cfg reg_cfg;
+} __packed;
+
+/*
+ * reg_data's size can be up to AFE_MAX_CDC_REGISTERS_TO_CONFIG
+ */
+struct afe_svc_cmd_cdc_reg_cfg {
+ struct apr_hdr hdr;
+ struct afe_svc_cmd_set_param param;
+ struct afe_param_cdc_reg_cfg_payload reg_data[0];
+} __packed;
+
+struct afe_svc_cmd_init_cdc_reg_cfg {
+ struct apr_hdr hdr;
+ struct afe_svc_cmd_set_param param;
+ struct afe_port_param_data_v2 init;
+} __packed;
+
+struct afe_svc_cmd_sb_slave_cfg {
+ struct apr_hdr hdr;
+ struct afe_svc_cmd_set_param param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_cdc_slimbus_slave_cfg sb_slave_cfg;
+} __packed;
+
#endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/sound/lsm_params.h b/include/sound/lsm_params.h
new file mode 100644
index 0000000..0edd8b5
--- /dev/null
+++ b/include/sound/lsm_params.h
@@ -0,0 +1,36 @@
+#ifndef __LSM_PARAMS_H__
+#define __LSM_PARAMS_H__
+
+#include <linux/types.h>
+#include <sound/asound.h>
+
+#define SNDRV_LSM_VERSION SNDRV_PROTOCOL_VERSION(0, 1, 0)
+
+enum lsm_detection_mode {
+ LSM_MODE_KEYWORD_ONLY_DETECTION = 1,
+ LSM_MODE_USER_KEYWORD_DETECTION
+};
+
+struct snd_lsm_sound_model {
+ __u8 *data;
+ __u32 data_size;
+ enum lsm_detection_mode detection_mode;
+ __u16 min_keyw_confidence;
+ __u16 min_user_confidence;
+ bool detect_failure;
+};
+
+struct snd_lsm_event_status {
+ __u16 status;
+ __u16 payload_size;
+ __u8 payload[0];
+};
+
+#define SNDRV_LSM_REG_SND_MODEL _IOW('U', 0x00, struct snd_lsm_sound_model)
+#define SNDRV_LSM_DEREG_SND_MODEL _IOW('U', 0x01, int)
+#define SNDRV_LSM_EVENT_STATUS _IOW('U', 0x02, struct snd_lsm_event_status)
+#define SNDRV_LSM_ABORT_EVENT _IOW('U', 0x03, int)
+#define SNDRV_LSM_START _IOW('U', 0x04, int)
+#define SNDRV_LSM_STOP _IOW('U', 0x05, int)
+
+#endif
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index feac314..22ddbbc 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -64,24 +64,34 @@
IDX_SLIMBUS_3_TX = 22,
IDX_SLIMBUS_4_RX = 23,
IDX_SLIMBUS_4_TX = 24,
- IDX_INT_BT_SCO_RX = 25,
- IDX_INT_BT_SCO_TX = 26,
- IDX_INT_BT_A2DP_RX = 27,
- IDX_INT_FM_RX = 28,
- IDX_INT_FM_TX = 29,
- IDX_RT_PROXY_PORT_001_RX = 30,
- IDX_RT_PROXY_PORT_001_TX = 31,
- IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX = 32,
- IDX_AFE_PORT_ID_QUATERNARY_MI2S_TX = 33,
- IDX_AFE_PORT_ID_SECONDARY_MI2S_RX = 34,
- IDX_AFE_PORT_ID_SECONDARY_MI2S_TX = 35,
- IDX_AFE_PORT_ID_TERTIARY_MI2S_RX = 36,
- IDX_AFE_PORT_ID_TERTIARY_MI2S_TX = 37,
- IDX_AFE_PORT_ID_PRIMARY_MI2S_RX = 38,
- IDX_AFE_PORT_ID_PRIMARY_MI2S_TX = 39,
+ IDX_SLIMBUS_5_RX = 25,
+ IDX_SLIMBUS_5_TX = 26,
+ IDX_INT_BT_SCO_RX = 27,
+ IDX_INT_BT_SCO_TX = 28,
+ IDX_INT_BT_A2DP_RX = 29,
+ IDX_INT_FM_RX = 30,
+ IDX_INT_FM_TX = 31,
+ IDX_RT_PROXY_PORT_001_RX = 32,
+ IDX_RT_PROXY_PORT_001_TX = 33,
+ IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX = 34,
+ IDX_AFE_PORT_ID_QUATERNARY_MI2S_TX = 35,
+ IDX_AFE_PORT_ID_SECONDARY_MI2S_RX = 36,
+ IDX_AFE_PORT_ID_SECONDARY_MI2S_TX = 37,
+ IDX_AFE_PORT_ID_TERTIARY_MI2S_RX = 38,
+ IDX_AFE_PORT_ID_TERTIARY_MI2S_TX = 39,
+ IDX_AFE_PORT_ID_PRIMARY_MI2S_RX = 40,
+ IDX_AFE_PORT_ID_PRIMARY_MI2S_TX = 41,
+ IDX_GLOBAL_CFG,
AFE_MAX_PORTS
};
+enum afe_mad_type {
+ MAD_HW_NONE = 0x00,
+ MAD_HW_AUDIO = 0x01,
+ MAD_HW_BEACON = 0x02,
+ MAD_HW_ULTRASOUND = 0x04
+};
+
struct afe_audio_buffer {
dma_addr_t phys;
void *data;
@@ -172,4 +182,10 @@
struct afe_digital_clk_cfg *cfg);
int q6afe_check_osr_clk_freq(u32 freq);
+int afe_turn_onoff_hw_mad(u16 mad_type, u16 mad_enable);
+int afe_port_set_mad_type(u16 port_id, enum afe_mad_type mad_type);
+enum afe_mad_type afe_port_get_mad_type(u16 port_id);
+int afe_set_config(enum afe_config_type config_type, void *config_data,
+ int arg);
+
#endif /* __Q6AFE_V2_H__ */
diff --git a/include/sound/q6lsm.h b/include/sound/q6lsm.h
new file mode 100644
index 0000000..5c9d4b9
--- /dev/null
+++ b/include/sound/q6lsm.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2013, Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __Q6LSM_H__
+#define __Q6LSM_H__
+
+#include <linux/list.h>
+#include <linux/msm_ion.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/lsm_params.h>
+#include <mach/qdsp6v2/apr.h>
+#include <mach/msm_subsystem_map.h>
+
+typedef void (*app_cb)(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv);
+
+struct lsm_sound_model {
+ dma_addr_t phys;
+ void *data;
+ uint32_t size; /* size of buffer */
+ uint32_t actual_size; /* actual number of bytes read by DSP */
+ struct ion_handle *handle;
+ struct ion_client *client;
+ uint32_t mem_map_handle;
+};
+
+struct lsm_client {
+ int session;
+ app_cb cb;
+ atomic_t cmd_state;
+ void *priv;
+ struct apr_svc *apr;
+ struct apr_svc *mmap_apr;
+ struct mutex cmd_lock;
+ struct lsm_sound_model sound_model;
+ wait_queue_head_t cmd_wait;
+ uint16_t mode;
+ uint16_t connect_to_port;
+ uint16_t user_sensitivity;
+ uint16_t kw_sensitivity;
+ bool started;
+};
+
+struct lsm_stream_cmd_open_tx {
+ struct apr_hdr hdr;
+ uint16_t app_id;
+ uint16_t reserved;
+ uint32_t sampling_rate;
+} __packed;
+
+struct lsm_param_payload_common {
+ uint32_t module_id;
+ uint32_t param_id;
+ uint16_t param_size;
+ uint16_t reserved;
+} __packed;
+
+struct lsm_param_op_mode {
+ struct lsm_param_payload_common common;
+ uint32_t minor_version;
+ uint16_t mode;
+ uint16_t reserved;
+} __packed;
+
+struct lsm_param_connect_to_port {
+ struct lsm_param_payload_common common;
+ uint32_t minor_version;
+ /* AFE port id that receives voice wake up data */
+ uint16_t port_id;
+ uint16_t reserved;
+} __packed;
+
+struct lsm_param_kw_detect_sensitivity {
+ struct lsm_param_payload_common common;
+ uint32_t minor_version;
+ /* scale factor to change the keyword confidence thresholds */
+ uint16_t keyword_sensitivity;
+ uint16_t reserved;
+} __packed;
+
+struct lsm_param_user_detect_sensitivity {
+ struct lsm_param_payload_common common;
+ uint32_t minor_version;
+ /* scale factor to change the user confidence thresholds */
+ uint16_t user_sensitivity;
+ uint16_t reserved;
+} __packed;
+
+struct lsm_params_payload {
+ struct lsm_param_connect_to_port connect_to_port;
+ struct lsm_param_op_mode op_mode;
+ struct lsm_param_kw_detect_sensitivity kwds;
+ struct lsm_param_user_detect_sensitivity uds;
+} __packed;
+
+struct lsm_cmd_set_params {
+ struct apr_hdr hdr;
+ uint32_t data_payload_size;
+ uint32_t data_payload_addr_lsw;
+ uint32_t data_payload_addr_msw;
+ uint32_t mem_map_handle;
+ struct lsm_params_payload payload;
+} __packed;
+
+struct lsm_cmd_reg_snd_model {
+ struct apr_hdr hdr;
+ uint32_t model_size;
+ uint32_t model_addr_lsw;
+ uint32_t model_addr_msw;
+ uint32_t mem_map_handle;
+} __packed;
+
+struct lsm_client *q6lsm_client_alloc(app_cb cb, void *priv);
+void q6lsm_client_free(struct lsm_client *client);
+int q6lsm_open(struct lsm_client *client);
+int q6lsm_start(struct lsm_client *client, bool wait);
+int q6lsm_stop(struct lsm_client *client, bool wait);
+int q6lsm_snd_model_buf_alloc(struct lsm_client *client, uint32_t len);
+int q6lsm_close(struct lsm_client *client);
+int q6lsm_register_sound_model(struct lsm_client *client,
+ enum lsm_detection_mode mode, u16 minkeyword,
+ u16 minuser, bool detectfailure);
+int q6lsm_deregister_sound_model(struct lsm_client *client);
+
+#endif /* __Q6LSM_H__ */
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 4636247..7403b40 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1534,6 +1534,20 @@
err = substream->ops->ioctl(substream, cmd, arg);
return err;
}
+
+static int snd_user_ioctl(struct snd_pcm_substream *substream,
+ unsigned int cmd, void __user *arg)
+{
+ struct snd_pcm_runtime *runtime;
+ int err = 0;
+
+ if (PCM_RUNTIME_CHECK(substream))
+ return -ENXIO;
+ runtime = substream->runtime;
+ err = substream->ops->ioctl(substream, cmd, arg);
+ return err;
+}
+
/*
* drop ioctl
*
@@ -2605,6 +2619,9 @@
case SNDRV_COMPRESS_TSTAMP:
case SNDRV_COMPRESS_DRAIN:
return snd_compressed_ioctl(substream, cmd, arg);
+ default:
+ if (((cmd >> 8) & 0xff) == 'U')
+ return snd_user_ioctl(substream, cmd, arg);
}
snd_printd("unknown ioctl = 0x%x\n", cmd);
return -ENOTTY;
@@ -2788,10 +2805,12 @@
unsigned long arg)
{
struct snd_pcm_file *pcm_file;
+ unsigned char ioctl_magic;
pcm_file = file->private_data;
+ ioctl_magic = ((cmd >> 8) & 0xff);
- if ((((cmd >> 8) & 0xff) != 'A') && (((cmd >> 8) & 0xff) != 'C'))
+ if (ioctl_magic != 'A' && ioctl_magic != 'C' && ioctl_magic != 'U')
return -ENOTTY;
return snd_pcm_capture_ioctl1(file, pcm_file->substream, cmd,
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 0c10548..78d1749 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -38,6 +38,9 @@
#include "wcd9xxx-resmgr.h"
#include "wcd9xxx-common.h"
+#define TAIKO_MAD_SLIMBUS_TX_PORT 12
+#define TAIKO_MAD_AUDIO_FIRMWARE_PATH "wcd9320/wcd9320_mad_audio.bin"
+
static atomic_t kp_taiko_priv;
static int spkr_drv_wrnd_param_set(const char *val,
const struct kernel_param *kp);
@@ -47,6 +50,121 @@
.set = spkr_drv_wrnd_param_set,
.get = param_get_int,
};
+
+static struct afe_param_slimbus_slave_port_cfg taiko_slimbus_slave_port_cfg = {
+ .minor_version = 1,
+ .slimbus_dev_id = AFE_SLIMBUS_DEVICE_1,
+ .slave_dev_pgd_la = 0,
+ .slave_dev_intfdev_la = 0,
+ .bit_width = 16,
+ .data_format = 0,
+ .num_channels = 1
+};
+
+enum {
+ RESERVED = 0,
+ AANC_LPF_FF_FB = 1,
+ AANC_LPF_COEFF_MSB,
+ AANC_LPF_COEFF_LSB,
+ HW_MAD_AUDIO_ENABLE,
+ HW_MAD_ULTR_ENABLE,
+ HW_MAD_BEACON_ENABLE,
+ HW_MAD_AUDIO_SLEEP_TIME,
+ HW_MAD_ULTR_SLEEP_TIME,
+ HW_MAD_BEACON_SLEEP_TIME,
+ HW_MAD_TX_AUDIO_SWITCH_OFF,
+ HW_MAD_TX_ULTR_SWITCH_OFF,
+ HW_MAD_TX_BEACON_SWITCH_OFF,
+ MAD_AUDIO_INT_DEST_SELECT_REG,
+ MAD_ULT_INT_DEST_SELECT_REG,
+ MAD_BEACON_INT_DEST_SELECT_REG,
+ MAD_CLIP_INT_DEST_SELECT_REG,
+ MAD_VBAT_INT_DEST_SELECT_REG,
+ MAD_AUDIO_INT_MASK_REG,
+ MAD_ULT_INT_MASK_REG,
+ MAD_BEACON_INT_MASK_REG,
+ MAD_CLIP_INT_MASK_REG,
+ MAD_VBAT_INT_MASK_REG,
+ MAD_AUDIO_INT_STATUS_REG,
+ MAD_ULT_INT_STATUS_REG,
+ MAD_BEACON_INT_STATUS_REG,
+ MAD_CLIP_INT_STATUS_REG,
+ MAD_VBAT_INT_STATUS_REG,
+ MAD_AUDIO_INT_CLEAR_REG,
+ MAD_ULT_INT_CLEAR_REG,
+ MAD_BEACON_INT_CLEAR_REG,
+ MAD_CLIP_INT_CLEAR_REG,
+ MAD_VBAT_INT_CLEAR_REG,
+ SB_PGD_PORT_TX_WATERMARK_n,
+ SB_PGD_PORT_TX_ENABLE_n,
+ SB_PGD_PORT_RX_WATERMARK_n,
+ SB_PGD_PORT_RX_ENABLE_n,
+ MAX_CFG_REGISTERS,
+};
+
+static struct afe_param_cdc_reg_cfg mad_audio_reg_cfg[] = {
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_MAD_MAIN_CTL_1),
+ HW_MAD_AUDIO_ENABLE, 0x1, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_MAD_AUDIO_CTL_3),
+ HW_MAD_AUDIO_SLEEP_TIME, 0xF, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_MAD_AUDIO_CTL_4),
+ HW_MAD_TX_AUDIO_SWITCH_OFF, 0x1, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_DESTN3),
+ MAD_AUDIO_INT_DEST_SELECT_REG, 0x1, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_MASK3),
+ MAD_AUDIO_INT_MASK_REG, 0x1, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_STATUS3),
+ MAD_AUDIO_INT_STATUS_REG, 0x1, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_CLEAR3),
+ MAD_AUDIO_INT_CLEAR_REG, 0x1, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_TX_BASE),
+ SB_PGD_PORT_TX_WATERMARK_n, 0x1E, 8, 0x1
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_TX_BASE),
+ SB_PGD_PORT_TX_ENABLE_n, 0x1, 8, 0x1
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_RX_BASE),
+ SB_PGD_PORT_RX_WATERMARK_n, 0x1E, 8, 0x1
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_RX_BASE),
+ SB_PGD_PORT_RX_ENABLE_n, 0x1, 8, 0x1
+ }
+};
+
+static struct afe_param_cdc_reg_cfg_data taiko_mad_audio_reg_cfg = {
+ .num_registers = ARRAY_SIZE(mad_audio_reg_cfg),
+ .reg_data = mad_audio_reg_cfg,
+};
+
module_param_cb(spkr_drv_wrnd, &spkr_drv_wrnd_param_ops, &spkr_drv_wrnd, 0644);
MODULE_PARM_DESC(spkr_drv_wrnd,
"Run software workaround to avoid leakage on the speaker drive");
@@ -84,6 +202,7 @@
AIF3_PB,
AIF3_CAP,
AIF4_VIFEED,
+ AIF4_MAD_TX,
NUM_CODEC_DAIS,
};
@@ -237,6 +356,8 @@
bool spkr_pa_widget_on;
+ struct afe_param_cdc_slimbus_slave_cfg slimbus_slave_cfg;
+
/* resmgr module */
struct wcd9xxx_resmgr resmgr;
/* mbhc module */
@@ -1555,6 +1676,9 @@
static const struct snd_kcontrol_new lineout4_ground_switch =
SOC_DAPM_SINGLE("Switch", TAIKO_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
+static const struct snd_kcontrol_new aif4_mad_switch =
+ SOC_DAPM_SINGLE("Switch", TAIKO_A_CDC_CLK_OTHR_CTL, 4, 1, 0);
+
/* virtual port entries */
static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -2155,6 +2279,108 @@
return 0;
}
+static int taiko_codec_config_mad(struct snd_soc_codec *codec)
+{
+ int ret;
+ const struct firmware *fw;
+ struct mad_audio_cal *mad_cal;
+ const char *filename = TAIKO_MAD_AUDIO_FIRMWARE_PATH;
+
+ pr_debug("%s: enter\n", __func__);
+ ret = request_firmware(&fw, filename, codec->dev);
+ if (ret != 0) {
+ pr_err("Failed to acquire MAD firwmare data %s: %d\n", filename,
+ ret);
+ return -ENODEV;
+ }
+
+ if (fw->size < sizeof(struct mad_audio_cal)) {
+ pr_err("%s: incorrect firmware size %u\n", __func__, fw->size);
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ mad_cal = (struct mad_audio_cal *)(fw->data);
+ if (!mad_cal) {
+ pr_err("%s: Invalid calibration data\n", __func__);
+ release_firmware(fw);
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CONN_MAD,
+ 0x0F, mad_cal->microphone_info.input_microphone);
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_MAIN_CTL_2,
+ mad_cal->microphone_info.cycle_time);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_MAIN_CTL_1, 0xFF << 3,
+ ((uint16_t)mad_cal->microphone_info.settle_time)
+ << 3);
+
+ /* Audio */
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_8,
+ mad_cal->audio_info.rms_omit_samples);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_1,
+ 0x07 << 4, mad_cal->audio_info.rms_comp_time << 4);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_2, 0x03 << 2,
+ mad_cal->audio_info.detection_mechanism << 2);
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_7,
+ mad_cal->audio_info.rms_diff_threshold & 0x3F);
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_5,
+ mad_cal->audio_info.rms_threshold_lsb);
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_6,
+ mad_cal->audio_info.rms_threshold_msb);
+
+
+ /* Beacon */
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_BEACON_CTL_8,
+ mad_cal->beacon_info.rms_omit_samples);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_BEACON_CTL_1,
+ 0x07 << 4, mad_cal->beacon_info.rms_comp_time);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_BEACON_CTL_2, 0x03 << 2,
+ mad_cal->beacon_info.detection_mechanism << 2);
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_BEACON_CTL_7,
+ mad_cal->beacon_info.rms_diff_threshold & 0x1F);
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_BEACON_CTL_5,
+ mad_cal->beacon_info.rms_threshold_lsb);
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_BEACON_CTL_6,
+ mad_cal->beacon_info.rms_threshold_msb);
+
+ /* Ultrasound */
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_BEACON_CTL_1,
+ 0x07 << 4, mad_cal->beacon_info.rms_comp_time);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_ULTR_CTL_2, 0x03 << 2,
+ mad_cal->ultrasound_info.detection_mechanism);
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_ULTR_CTL_7,
+ mad_cal->ultrasound_info.rms_diff_threshold & 0x1F);
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_ULTR_CTL_5,
+ mad_cal->ultrasound_info.rms_threshold_lsb);
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_ULTR_CTL_6,
+ mad_cal->ultrasound_info.rms_threshold_msb);
+
+ release_firmware(fw);
+ pr_debug("%s: leave ret %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int taiko_codec_enable_mad(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ int ret = 0;
+
+ pr_debug("%s %d\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = taiko_codec_config_mad(codec);
+ if (ret) {
+ pr_err("%s: Failed to config MAD\n", __func__);
+ break;
+ }
+ break;
+ }
+ return ret;
+}
+
static int taiko_codec_enable_micbias(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -2674,6 +2900,11 @@
{"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
{"AIF4 VI", NULL, "SPK_OUT"},
+ /* MAD */
+ {"AIF4 MAD", NULL, "CDC_CONN"},
+ {"MADONOFF", "Switch", "MADINPUT"},
+ {"AIF4 MAD", NULL, "MADONOFF"},
+
/* SLIM_MIXER("AIF1_CAP Mixer"),*/
{"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
{"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
@@ -3184,6 +3415,8 @@
static int taiko_volatile(struct snd_soc_codec *ssc, unsigned int reg)
{
+ int i;
+
/* Registers lower than 0x100 are top level registers which can be
* written by the Taiko core driver.
*/
@@ -3222,6 +3455,11 @@
return 1;
}
+ for (i = 0; i < ARRAY_SIZE(mad_audio_reg_cfg); i++)
+ if (mad_audio_reg_cfg[i].reg_logical_addr -
+ TAIKO_REGISTER_START_OFFSET == reg)
+ return 1;
+
return 0;
}
@@ -3428,6 +3666,7 @@
case AIF2_CAP:
case AIF3_CAP:
case AIF4_VIFEED:
+ case AIF4_MAD_TX:
if (!tx_slot || !tx_num) {
pr_err("%s: Invalid tx_slot %d or tx_num %d\n",
__func__, (u32) tx_slot, (u32) tx_num);
@@ -3858,6 +4097,20 @@
},
.ops = &taiko_dai_ops,
},
+ {
+ .name = "taiko_mad1",
+ .id = AIF4_MAD_TX,
+ .capture = {
+ .stream_name = "AIF4 MAD TX",
+ .rates = SNDRV_PCM_RATE_16000,
+ .formats = TAIKO_FORMATS,
+ .rate_min = 16000,
+ .rate_max = 16000,
+ .channels_min = 1,
+ .channels_max = 1,
+ },
+ .ops = &taiko_dai_ops,
+ },
};
static struct snd_soc_dai_driver taiko_i2s_dai[] = {
@@ -4556,6 +4809,12 @@
SND_SOC_DAPM_AIF_OUT_E("AIF4 VI", "VIfeed", 0, SND_SOC_NOPM,
AIF4_VIFEED, 0, taiko_codec_enable_slimvi_feedback,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_OUT_E("AIF4 MAD", "AIF4 MAD TX", 0,
+ SND_SOC_NOPM, 0, 0,
+ taiko_codec_enable_mad, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_SWITCH("MADONOFF", SND_SOC_NOPM, 0, 0,
+ &aif4_mad_switch),
+ SND_SOC_DAPM_INPUT("MADINPUT"),
SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
@@ -4884,6 +5143,26 @@
TAIKO_REG_VAL(TAIKO_A_CDC_RX5_B6_CTL, 0x80),
TAIKO_REG_VAL(TAIKO_A_CDC_RX6_B6_CTL, 0x80),
TAIKO_REG_VAL(TAIKO_A_CDC_RX7_B6_CTL, 0x80),
+
+ /* MAD registers */
+ TAIKO_REG_VAL(TAIKO_A_MAD_ANA_CTRL, 0xF1),
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_MAIN_CTL_1, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_MAIN_CTL_2, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_1, 0x00),
+ /* Set SAMPLE_TX_EN bit */
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_2, 0x03),
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_3, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_4, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_5, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_6, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_7, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_8, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_IIR_CTL_PTR, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_IIR_CTL_VAL, 0x40),
+ TAIKO_REG_VAL(TAIKO_A_CDC_DEBUG_B7_CTL, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_CLK_OTHR_RESET_B1_CTL, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_CLK_OTHR_CTL, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_CONN_MAD, 0x01),
};
static const struct wcd9xxx_reg_mask_val taiko_1_0_reg_defaults[] = {
@@ -5121,6 +5400,26 @@
}
EXPORT_SYMBOL_GPL(taiko_hs_detect);
+static void taiko_init_slim_slave_cfg(struct snd_soc_codec *codec)
+{
+ struct taiko_priv *priv = snd_soc_codec_get_drvdata(codec);
+ struct afe_param_cdc_slimbus_slave_cfg *cfg;
+ struct wcd9xxx *wcd9xxx = codec->control_data;
+ uint64_t eaddr = 0;
+
+ cfg = &priv->slimbus_slave_cfg;
+ cfg->minor_version = 1;
+ cfg->tx_slave_port_offset = 0;
+ cfg->rx_slave_port_offset = 16;
+
+ memcpy(&eaddr, &wcd9xxx->slim->e_addr, sizeof(wcd9xxx->slim->e_addr));
+ WARN_ON(sizeof(wcd9xxx->slim->e_addr) != 6);
+ cfg->device_enum_addr_lsw = eaddr & 0xFFFFFFFF;
+ cfg->device_enum_addr_msw = eaddr >> 32;
+
+ pr_debug("%s: slimbus logical address 0x%llx\n", __func__, eaddr);
+}
+
static int taiko_post_reset_cb(struct wcd9xxx *wcd9xxx)
{
int ret = 0;
@@ -5150,6 +5449,8 @@
if (IS_ERR_VALUE(ret))
pr_err("%s: bad pdata\n", __func__);
+ taiko_init_slim_slave_cfg(codec);
+
wcd9xxx_mbhc_deinit(&taiko->mbhc);
ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec);
if (ret)
@@ -5160,6 +5461,23 @@
return ret;
}
+void *taiko_get_afe_config(struct snd_soc_codec *codec,
+ enum afe_config_type config_type)
+{
+ struct taiko_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+ switch (config_type) {
+ case AFE_SLIMBUS_SLAVE_CONFIG:
+ return &priv->slimbus_slave_cfg;
+ case AFE_CDC_REGISTERS_CONFIG:
+ return &taiko_mad_audio_reg_cfg;
+ case AFE_SLIMBUS_SLAVE_PORT_CONFIG:
+ return &taiko_slimbus_slave_port_cfg;
+ default:
+ pr_err("%s: Unknown config_type 0x%x\n", __func__, config_type);
+ return NULL;
+ }
+}
static struct wcd9xxx_reg_address taiko_reg_address = {
.micb_4_mbhc = TAIKO_A_MICB_4_MBHC,
@@ -5353,6 +5671,14 @@
INIT_LIST_HEAD(&taiko->dai[i].wcd9xxx_ch_list);
init_waitqueue_head(&taiko->dai[i].dai_wait);
}
+ taiko_slimbus_slave_port_cfg.slave_dev_intfdev_la =
+ control->slim_slave->laddr;
+ taiko_slimbus_slave_port_cfg.slave_dev_pgd_la =
+ control->slim->laddr;
+ taiko_slimbus_slave_port_cfg.slave_port_mapping[0] =
+ TAIKO_MAD_SLIMBUS_TX_PORT;
+
+ taiko_init_slim_slave_cfg(codec);
}
if (TAIKO_IS_1_0(control->version))
diff --git a/sound/soc/codecs/wcd9320.h b/sound/soc/codecs/wcd9320.h
index 89a0b9f..36310e5 100644
--- a/sound/soc/codecs/wcd9320.h
+++ b/sound/soc/codecs/wcd9320.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,6 +14,7 @@
#include <sound/soc.h>
#include <sound/jack.h>
+#include <sound/apr_audio-v2.h>
#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
#include "wcd9xxx-mbhc.h"
#include "wcd9xxx-resmgr.h"
@@ -25,6 +26,10 @@
#define TAIKO_REG_VAL(reg, val) {reg, 0, val}
#define TAIKO_MCLK_ID 0
+#define TAIKO_REGISTER_START_OFFSET 0x800
+#define TAIKO_SB_PGD_PORT_RX_BASE 0x40
+#define TAIKO_SB_PGD_PORT_TX_BASE 0x50
+
extern const u8 taiko_reg_readable[TAIKO_CACHE_SIZE];
extern const u8 taiko_reset_reg_defaults[TAIKO_CACHE_SIZE];
struct taiko_codec_dai_data {
@@ -90,9 +95,62 @@
u32 num_anc_slots;
};
+struct mad_audio_header {
+ u32 reserved[3];
+ u32 num_reg_cfg;
+};
+
+struct mad_microphone_info {
+ uint8_t input_microphone;
+ uint8_t cycle_time;
+ uint8_t settle_time;
+ uint8_t padding;
+} __packed;
+
+struct mad_micbias_info {
+ uint8_t micbias;
+ uint8_t k_factor;
+ uint8_t external_bypass_capacitor;
+ uint8_t internal_biasing;
+ uint8_t cfilter;
+ uint8_t padding[3];
+} __packed;
+
+struct mad_rms_audio_beacon_info {
+ uint8_t rms_omit_samples;
+ uint8_t rms_comp_time;
+ uint8_t detection_mechanism;
+ uint8_t rms_diff_threshold;
+ uint8_t rms_threshold_lsb;
+ uint8_t rms_threshold_msb;
+ uint8_t padding[2];
+ uint8_t iir_coefficients[36];
+} __packed;
+
+struct mad_rms_ultrasound_info {
+ uint8_t rms_comp_time;
+ uint8_t detection_mechanism;
+ uint8_t rms_diff_threshold;
+ uint8_t rms_threshold_lsb;
+ uint8_t rms_threshold_msb;
+ uint8_t padding[3];
+ uint8_t iir_coefficients[36];
+} __packed;
+
+struct mad_audio_cal {
+ uint32_t version;
+ struct mad_microphone_info microphone_info;
+ struct mad_micbias_info micbias_info;
+ struct mad_rms_audio_beacon_info audio_info;
+ struct mad_rms_audio_beacon_info beacon_info;
+ struct mad_rms_ultrasound_info ultrasound_info;
+} __packed;
+
extern int taiko_mclk_enable(struct snd_soc_codec *codec, int mclk_enable,
bool dapm);
extern int taiko_hs_detect(struct snd_soc_codec *codec,
struct wcd9xxx_mbhc_config *mbhc_cfg);
+extern void *taiko_get_afe_config(struct snd_soc_codec *codec,
+ enum afe_config_type config_type);
#endif
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 96709be..e00e409 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -612,6 +612,20 @@
.ops = &msm_fe_dai_ops,
.name = "DTMF_RX_HOSTLESS",
},
+ {
+ .capture = {
+ .stream_name = "Listen Audio Service Capture",
+ .aif_name = "LSM_UL_HL",
+ .rates = SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_min = 16000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "LSM",
+ },
};
static __devinit int msm_fe_dai_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 747e027..0dbe3f7 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -24,6 +24,7 @@
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
#include <sound/jack.h>
+#include <sound/q6afe-v2.h>
#include <asm/mach-types.h>
#include <mach/socinfo.h>
#include <sound/pcm_params.h>
@@ -1003,6 +1004,33 @@
return 0;
}
+static int msm_slim_5_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ int rc;
+ void *config;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_interval *rate =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s enter\n", __func__);
+ rate->min = rate->max = 16000;
+ channels->min = channels->max = 1;
+
+ config = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_PORT_CONFIG);
+ rc = afe_set_config(AFE_SLIMBUS_SLAVE_PORT_CONFIG, config,
+ SLIMBUS_5_TX);
+ if (rc) {
+ pr_err("%s: Failed to set slimbus slave port config %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ return 0;
+}
+
static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -1054,6 +1082,7 @@
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
int err;
+ void *config_data;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@@ -1108,6 +1137,23 @@
snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+
+ config_data = taiko_get_afe_config(codec, AFE_CDC_REGISTERS_CONFIG);
+ err = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set codec registers config %d\n",
+ __func__, err);
+ return err;
+ }
+
+ config_data = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_CONFIG);
+ err = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set slimbus slave config %d\n", __func__,
+ err);
+ return err;
+ }
+
/* start mbhc */
mbhc_cfg.calibration = def_taiko_mbhc_cal();
if (mbhc_cfg.calibration)
@@ -1574,6 +1620,22 @@
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
},
+ /* LSM FE */
+ {
+ .name = "Listen Audio Service",
+ .stream_name = "Listen Audio Service",
+ .cpu_dai_name = "LSM",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM1,
+ },
/* Backend BT/FM DAI Links */
{
.name = LPASS_BE_INT_BT_SCO_RX,
@@ -1837,6 +1899,19 @@
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ignore_suspend = 1,
},
+ /* MAD BE */
+ {
+ .name = LPASS_BE_SLIMBUS_5_TX,
+ .stream_name = "Slimbus5 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16395",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_mad1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_5_TX,
+ .be_hw_params_fixup = msm_slim_5_tx_be_hw_params_fixup,
+ .ops = &msm8974_be_ops,
+ },
/* Incall Music BACK END DAI Link */
{
.name = LPASS_BE_VOICE_PLAYBACK_TX,
diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile
index 69c0976..391b3da 100644
--- a/sound/soc/msm/qdsp6v2/Makefile
+++ b/sound/soc/msm/qdsp6v2/Makefile
@@ -1,6 +1,11 @@
-snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o msm-pcm-routing-v2.o msm-compr-q6-v2.o msm-multi-ch-pcm-q6-v2.o
-snd-soc-qdsp6v2-objs += msm-pcm-lpa-v2.o msm-pcm-afe-v2.o msm-pcm-voip-v2.o msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o
-obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o msm-pcm-dtmf-v2.o msm-dai-stub-v2.o
-obj-y += q6adm.o q6afe.o q6asm.o q6audio-v2.o q6voice.o q6core.o audio_acdb.o rtac.o
+snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o msm-pcm-routing-v2.o \
+ msm-compr-q6-v2.o msm-multi-ch-pcm-q6-v2.o \
+ msm-pcm-lpa-v2.o msm-pcm-afe-v2.o msm-pcm-voip-v2.o \
+ msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o \
+ msm-lsm-client.o
+obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o msm-pcm-dtmf-v2.o \
+ msm-dai-stub-v2.o
+obj-y += q6adm.o q6afe.o q6asm.o q6audio-v2.o q6voice.o q6core.o audio_acdb.o \
+ rtac.o q6lsm.o
ocmem-audio-objs += audio_ocmem.o
obj-$(CONFIG_AUDIO_OCMEM) += ocmem-audio.o
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 557ec65..916be0b 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -701,6 +701,7 @@
case SLIMBUS_2_TX:
case SLIMBUS_3_TX:
case SLIMBUS_4_TX:
+ case SLIMBUS_5_TX:
rc = msm_dai_q6_slim_bus_hw_params(params, dai,
substream->stream);
break;
@@ -831,6 +832,7 @@
case SLIMBUS_2_TX:
case SLIMBUS_3_TX:
case SLIMBUS_4_TX:
+ case SLIMBUS_5_TX:
/*
* channel number to be between 128 and 255.
* For TX port use channel numbers
@@ -1980,6 +1982,7 @@
break;
case SLIMBUS_0_TX:
case SLIMBUS_2_TX:
+ case SLIMBUS_5_TX:
rc = snd_soc_register_dai(&pdev->dev,
&msm_dai_q6_slimbus_tx_dai);
break;
diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
new file mode 100644
index 0000000..ea6f390
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2013, Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/android_pmem.h>
+#include <linux/of.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/timer.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/q6lsm.h>
+#include <sound/lsm_params.h>
+#include "msm-pcm-routing-v2.h"
+
+struct lsm_priv {
+ struct snd_pcm_substream *substream;
+ struct lsm_client *lsm_client;
+
+ struct snd_lsm_event_status *event_status;
+ spinlock_t event_lock;
+ wait_queue_head_t event_wait;
+ unsigned long event_avail;
+ atomic_t event_wait_stop;
+};
+
+static void lsm_event_handler(uint32_t opcode, uint32_t token,
+ void *payload, void *priv)
+{
+ unsigned long flags;
+ struct snd_lsm_event_status *event_status;
+ struct lsm_priv *prtd = priv;
+ struct snd_pcm_substream *substream = prtd->substream;
+
+ pr_debug("%s: enter opcode 0x%x\n", __func__, opcode);
+ switch (opcode) {
+ case LSM_SESSION_EVENT_DETECTION_STATUS:
+ event_status = payload;
+
+ spin_lock_irqsave(&prtd->event_lock, flags);
+ prtd->event_status = krealloc(prtd->event_status,
+ sizeof(*event_status) +
+ event_status->payload_size,
+ GFP_ATOMIC);
+ if (likely(prtd->event_status)) {
+ memcpy(prtd->event_status, event_status,
+ sizeof(*event_status) +
+ event_status->payload_size);
+ prtd->event_avail = 1;
+ spin_unlock_irqrestore(&prtd->event_lock, flags);
+ wake_up(&prtd->event_wait);
+ } else {
+ spin_unlock_irqrestore(&prtd->event_lock, flags);
+ pr_err("%s: Couldn't allocate %d bytes of memory\n",
+ __func__, event_status->payload_size);
+ }
+ if (substream->timer_running)
+ snd_timer_interrupt(substream->timer, 1);
+ break;
+ default:
+ pr_debug("%s: Unsupported Event opcode 0x%x\n", __func__,
+ opcode);
+ break;
+ }
+}
+
+static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ unsigned long flags;
+ int ret;
+ struct snd_lsm_sound_model snd_model;
+ int rc = 0;
+ int xchg = 0;
+ int size = 0;
+ struct snd_lsm_event_status *event_status = NULL;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct lsm_priv *prtd = runtime->private_data;
+ struct snd_lsm_event_status *user = arg;
+
+ pr_debug("%s: enter cmd %x\n", __func__, cmd);
+ switch (cmd) {
+ case SNDRV_LSM_REG_SND_MODEL:
+ pr_debug("%s: Registering sound model\n", __func__);
+ if (copy_from_user(&snd_model, (void *)arg,
+ sizeof(struct snd_lsm_sound_model))) {
+ rc = -EFAULT;
+ pr_err("%s: copy from user failed, size %d\n", __func__,
+ sizeof(struct snd_lsm_sound_model));
+ break;
+ }
+
+ rc = q6lsm_snd_model_buf_alloc(prtd->lsm_client,
+ snd_model.data_size);
+ if (rc) {
+ pr_err("%s: q6lsm buffer alloc failed, size %d\n",
+ __func__, snd_model.data_size);
+ break;
+ }
+
+ if (copy_from_user(prtd->lsm_client->sound_model.data,
+ snd_model.data, snd_model.data_size)) {
+ pr_err("%s: copy from user data failed size %d\n",
+ __func__, snd_model.data_size);
+ rc = -EFAULT;
+ break;
+ }
+
+ rc = q6lsm_register_sound_model(prtd->lsm_client,
+ snd_model.detection_mode,
+ snd_model.min_keyw_confidence,
+ snd_model.min_user_confidence,
+ snd_model.detect_failure);
+ if (rc < 0)
+ pr_err("%s: q6lsm_register_sound_model failed =%d\n",
+ __func__, rc);
+ break;
+
+ case SNDRV_LSM_DEREG_SND_MODEL:
+ pr_debug("%s: Deregistering sound model\n", __func__);
+ rc = q6lsm_deregister_sound_model(prtd->lsm_client);
+ break;
+
+ case SNDRV_LSM_EVENT_STATUS:
+ pr_debug("%s: Get event status\n", __func__);
+ atomic_set(&prtd->event_wait_stop, 0);
+ rc = wait_event_interruptible(prtd->event_wait,
+ (cmpxchg(&prtd->event_avail, 1, 0) ||
+ (xchg = atomic_cmpxchg(&prtd->event_wait_stop,
+ 1, 0))));
+ pr_debug("%s: wait_event_interruptible %d event_wait_stop %d\n",
+ __func__, rc, xchg);
+ if (!rc && !xchg) {
+ pr_debug("%s: New event available %ld\n", __func__,
+ prtd->event_avail);
+ spin_lock_irqsave(&prtd->event_lock, flags);
+ if (prtd->event_status) {
+ size = sizeof(*event_status) +
+ prtd->event_status->payload_size;
+ event_status = kmemdup(prtd->event_status, size,
+ GFP_ATOMIC);
+ }
+ spin_unlock_irqrestore(&prtd->event_lock, flags);
+ if (!event_status) {
+ pr_err("%s: Couldn't allocate %d bytes\n",
+ __func__, size);
+ /*
+ * Don't use -ENOMEM as userspace will check
+ * it for increasing buffer
+ */
+ rc = -EFAULT;
+ } else {
+ if (user->payload_size <
+ event_status->payload_size) {
+ pr_debug("%s: provided %dbytes isn't enough, needs %dbytes\n",
+ __func__, user->payload_size,
+ size);
+ rc = -ENOMEM;
+ } else if (!access_ok(VERIFY_WRITE, arg,
+ size)) {
+ rc = -EFAULT;
+ } else {
+ rc = copy_to_user(arg, event_status,
+ size);
+ if (rc)
+ pr_err("%s: copy to user failed %d\n",
+ __func__, rc);
+ }
+ kfree(event_status);
+ }
+ } else if (xchg) {
+ pr_debug("%s: Wait aborted\n", __func__);
+ rc = 0;
+ }
+ break;
+
+ case SNDRV_LSM_ABORT_EVENT:
+ pr_debug("%s: Aborting event status wait\n", __func__);
+ atomic_set(&prtd->event_wait_stop, 1);
+ wake_up(&prtd->event_wait);
+ break;
+
+ case SNDRV_LSM_START:
+ pr_debug("%s: Starting LSM client session\n", __func__);
+ if (!prtd->lsm_client->started) {
+ ret = q6lsm_start(prtd->lsm_client, true);
+ if (!ret) {
+ prtd->lsm_client->started = true;
+ pr_debug("%s: LSM client session started\n",
+ __func__);
+ }
+ }
+ break;
+
+ case SNDRV_LSM_STOP:
+ pr_debug("%s: Stopping LSM client session\n", __func__);
+ if (prtd->lsm_client->started) {
+ ret = q6lsm_stop(prtd->lsm_client, true);
+ if (!ret) {
+ prtd->lsm_client->started = false;
+ pr_debug("%s: LSM client session stopped\n",
+ __func__);
+ }
+ }
+ break;
+
+ default:
+ pr_debug("%s: Falling into default snd_lib_ioctl cmd 0x%x\n",
+ __func__, cmd);
+ rc = snd_pcm_lib_ioctl(substream, cmd, arg);
+ break;
+ }
+
+ if (!rc)
+ pr_debug("%s: leave (%d)\n", __func__, rc);
+ else
+ pr_err("%s: cmd 0x%x failed %d\n", __func__, cmd, rc);
+
+ return rc;
+}
+
+static int msm_lsm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct lsm_priv *prtd;
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+ prtd = kzalloc(sizeof(struct lsm_priv), GFP_KERNEL);
+ if (!prtd) {
+ pr_err("%s: Failed to allocate memory for lsm_priv\n",
+ __func__);
+ return -ENOMEM;
+ }
+ prtd->substream = substream;
+ prtd->lsm_client = q6lsm_client_alloc((app_cb)lsm_event_handler, prtd);
+ if (!prtd->lsm_client) {
+ pr_err("%s: Could not allocate memory\n", __func__);
+ kfree(prtd);
+ return -ENOMEM;
+ }
+ ret = q6lsm_open(prtd->lsm_client);
+ if (ret < 0) {
+ pr_err("%s: lsm out open failed\n", __func__);
+ q6lsm_client_free(prtd->lsm_client);
+ kfree(prtd);
+ return -ENOMEM;
+ }
+
+ pr_debug("%s: Session ID %d\n", __func__, prtd->lsm_client->session);
+ prtd->lsm_client->started = false;
+ spin_lock_init(&prtd->event_lock);
+ init_waitqueue_head(&prtd->event_wait);
+ runtime->private_data = prtd;
+
+ return 0;
+}
+
+static int msm_lsm_close(struct snd_pcm_substream *substream)
+{
+ unsigned long flags;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct lsm_priv *prtd = runtime->private_data;
+
+ pr_debug("%s\n", __func__);
+
+ q6lsm_close(prtd->lsm_client);
+ q6lsm_client_free(prtd->lsm_client);
+
+ spin_lock_irqsave(&prtd->event_lock, flags);
+ kfree(prtd->event_status);
+ prtd->event_status = NULL;
+ spin_unlock_irqrestore(&prtd->event_lock, flags);
+ kfree(prtd);
+
+ return 0;
+}
+
+static struct snd_pcm_ops msm_lsm_ops = {
+ .open = msm_lsm_open,
+ .close = msm_lsm_close,
+ .ioctl = msm_lsm_ioctl,
+};
+
+static int msm_asoc_lsm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_card *card = rtd->card->snd_card;
+
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ return 0;
+}
+
+static int msm_asoc_lsm_probe(struct snd_soc_platform *platform)
+{
+ pr_debug("enter %s\n", __func__);
+
+ return 0;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .ops = &msm_lsm_ops,
+ .pcm_new = msm_asoc_lsm_new,
+ .probe = msm_asoc_lsm_probe,
+};
+
+static __devinit int msm_lsm_probe(struct platform_device *pdev)
+{
+ if (pdev->dev.of_node)
+ dev_set_name(&pdev->dev, "%s", "msm-lsm-client");
+
+ return snd_soc_register_platform(&pdev->dev, &msm_soc_platform);
+}
+
+static int msm_lsm_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id msm_lsm_client_dt_match[] = {
+ {.compatible = "qcom,msm-lsm-client" },
+ { }
+};
+
+static struct platform_driver msm_lsm_driver = {
+ .driver = {
+ .name = "msm-lsm-client",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(msm_lsm_client_dt_match),
+ },
+ .probe = msm_lsm_probe,
+ .remove = __devexit_p(msm_lsm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ return platform_driver_register(&msm_lsm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ platform_driver_unregister(&msm_lsm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("LSM client platform driver");
+MODULE_DEVICE_TABLE(of, msm_lsm_client_dt_match);
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 9fe438c..819512d 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -55,6 +55,27 @@
static int fm_switch_enable;
static int fm_pcmrx_switch_enable;
static int srs_alsa_ctrl_ever_called;
+static int lsm_mux_slim_port;
+
+enum {
+ MADNONE,
+ MADAUDIO,
+ MADBEACON,
+ MADULTRASOUND
+};
+
+#define SLIMBUS_0_TX_TEXT "SLIMBUS_0_TX"
+#define SLIMBUS_1_TX_TEXT "SLIMBUS_1_TX"
+#define SLIMBUS_2_TX_TEXT "SLIMBUS_2_TX"
+#define SLIMBUS_3_TX_TEXT "SLIMBUS_3_TX"
+#define SLIMBUS_4_TX_TEXT "SLIMBUS_4_TX"
+#define SLIMBUS_5_TX_TEXT "SLIMBUS_5_TX"
+#define LSM_FUNCTION_TEXT "LSM Function"
+static const char * const mad_audio_mux_text[] = {
+ "None",
+ SLIMBUS_0_TX_TEXT, SLIMBUS_1_TX_TEXT, SLIMBUS_2_TX_TEXT,
+ SLIMBUS_3_TX_TEXT, SLIMBUS_4_TX_TEXT, SLIMBUS_5_TX_TEXT
+};
#define INT_RX_VOL_MAX_STEPS 0x2000
#define INT_RX_VOL_GAIN 0x2000
@@ -190,6 +211,7 @@
{ SLIMBUS_4_TX, 0, 0, 0, 0, 0},
{ SLIMBUS_3_RX, 0, 0, 0, 0, 0},
{ SLIMBUS_3_TX, 0, 0, 0, 0, 0},
+ { SLIMBUS_5_TX, 0, 0, 0, 0, 0 },
{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
@@ -731,6 +753,118 @@
return 1;
}
+static int msm_routing_lsm_mux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = lsm_mux_slim_port;
+ return 0;
+}
+
+static int msm_routing_lsm_mux_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ int mux = ucontrol->value.enumerated.item[0];
+
+ pr_debug("%s: LSM enable %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ if (ucontrol->value.integer.value[0]) {
+ lsm_mux_slim_port = ucontrol->value.integer.value[0];
+ snd_soc_dapm_mux_update_power(widget, kcontrol, 1, mux, e);
+ } else {
+ snd_soc_dapm_mux_update_power(widget, kcontrol, 1, mux, e);
+ lsm_mux_slim_port = ucontrol->value.integer.value[0];
+ }
+
+ return 0;
+}
+
+static int msm_routing_lsm_func_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+ u16 port_id;
+ enum afe_mad_type mad_type;
+
+ pr_debug("%s: enter\n", __func__);
+ for (i = 0; i < ARRAY_SIZE(mad_audio_mux_text); i++)
+ if (!strncmp(kcontrol->id.name, mad_audio_mux_text[i],
+ strlen(mad_audio_mux_text[i])))
+ break;
+
+ if (i-- == ARRAY_SIZE(mad_audio_mux_text)) {
+ WARN(1, "Invalid id name %s\n", kcontrol->id.name);
+ return -EINVAL;
+ }
+
+ port_id = i * 2 + 1 + SLIMBUS_0_RX;
+ mad_type = afe_port_get_mad_type(port_id);
+ pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
+ mad_type);
+ switch (mad_type) {
+ case MAD_HW_NONE:
+ ucontrol->value.integer.value[0] = MADNONE;
+ break;
+ case MAD_HW_AUDIO:
+ ucontrol->value.integer.value[0] = MADAUDIO;
+ break;
+ case MAD_HW_BEACON:
+ ucontrol->value.integer.value[0] = MADBEACON;
+ break;
+ case MAD_HW_ULTRASOUND:
+ ucontrol->value.integer.value[0] = MADULTRASOUND;
+ break;
+ default:
+ WARN(1, "Unknown\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int msm_routing_lsm_func_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+ u16 port_id;
+ enum afe_mad_type mad_type;
+
+ pr_debug("%s: enter\n", __func__);
+ for (i = 0; i < ARRAY_SIZE(mad_audio_mux_text); i++)
+ if (!strncmp(kcontrol->id.name, mad_audio_mux_text[i],
+ strlen(mad_audio_mux_text[i])))
+ break;
+
+ if (i-- == ARRAY_SIZE(mad_audio_mux_text)) {
+ WARN(1, "Invalid id name %s\n", kcontrol->id.name);
+ return -EINVAL;
+ }
+
+ port_id = i * 2 + 1 + SLIMBUS_0_RX;
+ switch (ucontrol->value.integer.value[0]) {
+ case MADNONE:
+ mad_type = MAD_HW_NONE;
+ break;
+ case MADAUDIO:
+ mad_type = MAD_HW_AUDIO;
+ break;
+ case MADBEACON:
+ mad_type = MAD_HW_BEACON;
+ break;
+ case MADULTRASOUND:
+ mad_type = MAD_HW_ULTRASOUND;
+ break;
+ default:
+ WARN(1, "Unknown\n");
+ return -EINVAL;
+ }
+
+ pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
+ mad_type);
+ return afe_port_set_mad_type(port_id, mad_type);
+}
+
static int msm_routing_get_port_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1734,6 +1868,33 @@
0, 1, 0, msm_routing_get_fm_pcmrx_switch_mixer,
msm_routing_put_fm_pcmrx_switch_mixer);
+static const struct soc_enum lsm_mux_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mad_audio_mux_text), mad_audio_mux_text);
+static const struct snd_kcontrol_new lsm_mux =
+ SOC_DAPM_ENUM_EXT("LSM1 MUX", lsm_mux_enum,
+ msm_routing_lsm_mux_get,
+ msm_routing_lsm_mux_put);
+
+static const char * const lsm_func_text[] = {
+ "None", "AUDIO", "BEACON", "ULTRASOUND"
+};
+static const struct soc_enum lsm_func_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lsm_func_text), lsm_func_text);
+static const struct snd_kcontrol_new lsm_function[] = {
+ SOC_ENUM_EXT(SLIMBUS_0_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+ msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+ SOC_ENUM_EXT(SLIMBUS_1_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+ msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+ SOC_ENUM_EXT(SLIMBUS_2_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+ msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+ SOC_ENUM_EXT(SLIMBUS_3_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+ msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+ SOC_ENUM_EXT(SLIMBUS_4_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+ msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+ SOC_ENUM_EXT(SLIMBUS_5_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+ msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+};
+
static const struct snd_kcontrol_new int_fm_vol_mixer_controls[] = {
SOC_SINGLE_EXT_TLV("Internal FM RX Volume", SND_SOC_NOPM, 0,
INT_RX_VOL_GAIN, 0, msm_routing_get_fm_vol_mixer,
@@ -2111,6 +2272,9 @@
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("DTMF_DL_HL", "DTMF_RX_HOSTLESS Playback",
0, 0, 0, 0),
+ /* LSM */
+ SND_SOC_DAPM_AIF_OUT("LSM_UL_HL", "Listen Audio Service Capture",
+ 0, 0, 0, 0),
/* Backend AIF */
/* Stream name equals to backend dai link stream name
*/
@@ -2156,6 +2320,7 @@
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SLIMBUS_4_TX", "Slimbus4 Capture",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIMBUS_5_TX", "Slimbus5 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("AUX_PCM_RX", "AUX PCM Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("AUX_PCM_TX", "AUX PCM Capture", 0, 0, 0, 0),
@@ -2180,6 +2345,10 @@
&fm_switch_mixer_controls),
SND_SOC_DAPM_SWITCH("PCM_RX_DL_HL", SND_SOC_NOPM, 0, 0,
&pcm_rx_switch_mixer_controls),
+
+ /* Mux Definitions */
+ SND_SOC_DAPM_MUX("LSM1 MUX", SND_SOC_NOPM, 0, 0, &lsm_mux),
+
/* Mixer definitions */
SND_SOC_DAPM_MIXER("PRI_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
pri_i2s_rx_mixer_controls, ARRAY_SIZE(pri_i2s_rx_mixer_controls)),
@@ -2514,6 +2683,14 @@
{"SLIM1_UL_HL", NULL, "SLIMBUS_1_TX"},
{"SLIM3_UL_HL", NULL, "SLIMBUS_3_TX"},
{"SLIM4_UL_HL", NULL, "SLIMBUS_4_TX"},
+
+ {"LSM1 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM1 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM1 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM1 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM1 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM_UL_HL", NULL, "LSM1 MUX"},
+
{"INT_FM_RX", NULL, "INTFM_DL_HL"},
{"INTFM_UL_HL", NULL, "INT_FM_TX"},
{"AUX_PCM_RX", NULL, "AUXPCM_DL_HL"},
@@ -2600,6 +2777,7 @@
{"SLIMBUS_1_TX", NULL, "BE_IN" },
{"SLIMBUS_3_TX", NULL, "BE_IN" },
{"SLIMBUS_4_TX", NULL, "BE_IN" },
+ {"SLIMBUS_5_TX", NULL, "BE_IN" },
{"BE_OUT", NULL, "INT_BT_SCO_RX"},
{"INT_BT_SCO_TX", NULL, "BE_IN"},
{"BE_OUT", NULL, "INT_FM_RX"},
@@ -2821,6 +2999,9 @@
snd_soc_add_platform_controls(platform,
multi_ch_channel_map_mixer_controls,
ARRAY_SIZE(multi_ch_channel_map_mixer_controls));
+
+ snd_soc_add_platform_controls(platform, lsm_function,
+ ARRAY_SIZE(lsm_function));
return 0;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 7ecdff3..798f676 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -51,6 +51,7 @@
#define LPASS_BE_SLIMBUS_3_TX "SLIMBUS_3_TX"
#define LPASS_BE_SLIMBUS_4_RX "SLIMBUS_4_RX"
#define LPASS_BE_SLIMBUS_4_TX "SLIMBUS_4_TX"
+#define LPASS_BE_SLIMBUS_5_TX "SLIMBUS_5_TX"
/* For multimedia front-ends, asm session is allocated dynamically.
* Hence, asm session/multimedia front-end mapping has to be maintained.
@@ -71,6 +72,7 @@
MSM_FRONTEND_DAI_VOICE_STUB,
MSM_FRONTEND_DAI_VOLTE,
MSM_FRONTEND_DAI_DTMF_RX,
+ MSM_FRONTEND_DAI_LSM1,
MSM_FRONTEND_DAI_MAX,
};
@@ -103,6 +105,7 @@
MSM_BACKEND_DAI_SLIMBUS_4_TX,
MSM_BACKEND_DAI_SLIMBUS_3_RX,
MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ MSM_BACKEND_DAI_SLIMBUS_5_TX,
MSM_BACKEND_DAI_EXTPROC_RX,
MSM_BACKEND_DAI_EXTPROC_TX,
MSM_BACKEND_DAI_EXTPROC_EC_TX,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
index d0b119c..a25fb2a 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -11,7 +11,7 @@
*/
#ifndef _MSM_PCM_VOICE_H
#define _MSM_PCM_VOICE_H
-#include <sound/apr_audio.h>
+#include <sound/apr_audio-v2.h>
enum {
VOICE_SESSION_INDEX,
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 5e1da59..97cd3fc 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -9,7 +9,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-
#include <linux/slab.h>
#include <linux/debugfs.h>
#include <linux/kernel.h>
@@ -22,6 +21,7 @@
#include <sound/apr_audio-v2.h>
#include <sound/q6afe-v2.h>
#include <sound/q6audio-v2.h>
+#include "msm-pcm-routing-v2.h"
#include "audio_acdb.h"
@@ -47,6 +47,8 @@
int vi_tx_port;
};
+static atomic_t afe_ports_mad_type[SLIMBUS_PORT_LAST - SLIMBUS_0_RX];
+
static struct afe_ctl this_afe;
#define TIMEOUT_MS 1000
@@ -121,6 +123,7 @@
case AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS:
case AFE_SERVICE_CMD_UNREGISTER_RT_PORT_DRIVER:
case AFE_PORTS_CMD_DTMF_CTL:
+ case AFE_SVC_CMD_SET_PARAM:
atomic_set(&this_afe.state, 0);
wake_up(&this_afe.wait[data->token]);
break;
@@ -218,6 +221,7 @@
case SLIMBUS_2_TX:
case SLIMBUS_3_TX:
case SLIMBUS_4_TX:
+ case SLIMBUS_5_TX:
case INT_FM_TX:
case VOICE_RECORD_RX:
case INT_BT_SCO_TX:
@@ -298,6 +302,37 @@
return ret;
}
+/*
+ * afe_apr_send_pkt : returns 0 on success, negative otherwise.
+ */
+static int afe_apr_send_pkt(void *data, wait_queue_head_t *wait)
+{
+ int ret;
+
+ atomic_set(&this_afe.state, 1);
+ atomic_set(&this_afe.status, 0);
+ ret = apr_send_pkt(this_afe.apr, data);
+ if (ret > 0) {
+ if (wait) {
+ ret = wait_event_timeout(*wait,
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (ret)
+ ret = 0;
+ else
+ ret = -ETIMEDOUT;
+ } else {
+ ret = 0;
+ }
+ } else if (ret == 0) {
+ /* apr_send_pkt can return 0 when nothing is transmitted */
+ ret = -EINVAL;
+ }
+
+ pr_debug("%s: leave %d\n", __func__, ret);
+ return ret;
+}
+
static void afe_send_cal_block(int32_t path, u16 port_id)
{
int result = 0;
@@ -350,22 +385,13 @@
__func__, port_id, path,
cal_block.cal_size, cal_block.cal_paddr);
- atomic_set(&this_afe.state, 1);
- result = apr_send_pkt(this_afe.apr, (uint32_t *) &afe_cal);
- if (result < 0) {
- pr_err("%s: AFE cal for port %d failed\n",
- __func__, port_id);
- }
-
- result = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!result) {
- pr_err("%s: wait_event timeout SET AFE CAL\n", __func__);
- goto done;
- }
-
- pr_debug("%s: AFE cal sent for path %d device!\n", __func__, path);
+ result = afe_apr_send_pkt(&afe_cal, &this_afe.wait[index]);
+ if (result)
+ pr_err("%s: AFE cal for port %d failed %d\n",
+ __func__, port_id, result);
+ else
+ pr_debug("%s: AFE cal sent for path %d device!\n", __func__,
+ path);
done:
return;
}
@@ -506,14 +532,319 @@
}
}
+int afe_turn_onoff_hw_mad(u16 mad_type, u16 enable)
+{
+ int ret;
+ struct afe_cmd_hw_mad_ctrl config;
+
+ pr_debug("%s: enter\n", __func__);
+ memset(&config, 0, sizeof(config));
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = IDX_GLOBAL_CFG;
+ config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ config.param.port_id = SLIMBUS_5_TX;
+ config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+ sizeof(config.param);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_HW_MAD;
+ config.pdata.param_id = AFE_PARAM_ID_HW_MAD_CTRL;
+ config.pdata.param_size = sizeof(config.payload);
+ config.payload.minor_version = 1;
+ config.payload.mad_type = mad_type;
+ config.payload.mad_enable = enable;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (ret)
+ pr_err("%s: AFE_PARAM_ID_HW_MAD_CTRL failed %d\n", __func__,
+ ret);
+ return ret;
+}
+
+static int afe_send_slimbus_slave_cfg(
+ struct afe_param_cdc_slimbus_slave_cfg *sb_slave_cfg)
+{
+ int ret;
+ struct afe_svc_cmd_sb_slave_cfg config;
+
+ pr_debug("%s: enter\n", __func__);
+
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = IDX_GLOBAL_CFG;
+ config.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+ config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+ sizeof(config.param);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_CDC_DEV_CFG;
+ config.pdata.param_id = AFE_PARAM_ID_CDC_SLIMBUS_SLAVE_CFG;
+ config.pdata.param_size =
+ sizeof(struct afe_param_cdc_slimbus_slave_cfg);
+ config.sb_slave_cfg = *sb_slave_cfg;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (ret)
+ pr_err("%s: AFE_PARAM_ID_CDC_SLIMBUS_SLAVE_CFG failed %d\n",
+ __func__, ret);
+
+ pr_debug("%s: leave %d\n", __func__, ret);
+ return ret;
+}
+
+static int afe_send_codec_reg_config(
+ struct afe_param_cdc_reg_cfg_data *cdc_reg_cfg)
+{
+ int i, ret;
+ int pkt_size, payload_size;
+ struct afe_svc_cmd_cdc_reg_cfg *config;
+ struct afe_svc_cmd_set_param *param;
+
+ pr_debug("%s: enter\n", __func__);
+ payload_size = sizeof(struct afe_param_cdc_reg_cfg_payload) *
+ cdc_reg_cfg->num_registers;
+ pkt_size = sizeof(*config) + payload_size;
+
+ pr_debug("%s: pkt_size %d, payload %d\n", __func__, pkt_size,
+ payload_size);
+ config = kzalloc(pkt_size, GFP_KERNEL);
+ if (!config) {
+ pr_warn("%s: Not enought memory, pkt_size %d\n", __func__,
+ pkt_size);
+ return -ENOMEM;
+ }
+
+ config->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ config->hdr.pkt_size = pkt_size;
+ config->hdr.src_port = 0;
+ config->hdr.dest_port = 0;
+ config->hdr.token = IDX_GLOBAL_CFG;
+ config->hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+
+ param = &config->param;
+ param->payload_size = payload_size;
+ param->payload_address_lsw = 0x00;
+ param->payload_address_msw = 0x00;
+ param->mem_map_handle = 0x00;
+
+ for (i = 0; i < cdc_reg_cfg->num_registers; i++) {
+ config->reg_data[i].common.module_id = AFE_MODULE_CDC_DEV_CFG;
+ config->reg_data[i].common.param_id = AFE_PARAM_ID_CDC_REG_CFG;
+ config->reg_data[i].common.param_size =
+ sizeof(config->reg_data[i].reg_cfg);
+ config->reg_data[i].reg_cfg = cdc_reg_cfg->reg_data[i];
+ }
+
+ ret = afe_apr_send_pkt(config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (ret)
+ pr_err("%s: AFE_PARAM_ID_CDC_REG_CFG failed %d\n", __func__,
+ ret);
+
+ kfree(config);
+ pr_debug("%s: leave ret %d\n", __func__, ret);
+ return ret;
+}
+
+static int afe_init_cdc_reg_config(void)
+{
+ int ret;
+ struct afe_svc_cmd_init_cdc_reg_cfg config;
+
+ pr_debug("%s: enter\n", __func__);
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = IDX_GLOBAL_CFG;
+ config.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+
+ config.param.payload_size = sizeof(struct afe_port_param_data_v2);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+
+ config.init.module_id = AFE_MODULE_CDC_DEV_CFG;
+ config.init.param_id = AFE_PARAM_ID_CDC_REG_CFG_INIT;
+ config.init.param_size = 0;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (ret) {
+ pr_err("%s: AFE_PARAM_ID_CDC_INIT_REG_CFG failed %d\n",
+ __func__, ret);
+ } else if (atomic_read(&this_afe.status) != 0) {
+ pr_err("%s: config cmd failed\n", __func__);
+ ret = -EINVAL;
+ }
+
+ pr_debug("%s: leave ret %d\n", __func__, 0);
+ return ret;
+}
+
+static int afe_send_slimbus_slave_port_cfg(
+ struct afe_param_slimbus_slave_port_cfg *port_config, u16 port_id)
+{
+ int ret, index;
+ struct afe_cmd_hw_mad_slimbus_slave_port_cfg config;
+
+ pr_debug("%s: enter, port_id %u\n", __func__, port_id);
+ index = q6audio_get_port_index(port_id);
+ if (q6audio_validate_port(port_id) < 0) {
+ pr_err("%s: port id: %#x\n", __func__, port_id);
+ return -EINVAL;
+ }
+
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = index;
+ config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ config.param.port_id = port_id;
+ config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+ sizeof(config.param);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_HW_MAD;
+ config.pdata.param_id = AFE_PARAM_ID_SLIMBUS_SLAVE_PORT_CFG;
+ config.pdata.param_size = sizeof(*port_config);
+ config.sb_port_cfg = *port_config;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE_PARAM_ID_SLIMBUS_SLAVE_PORT_CFG failed %d\n",
+ __func__, ret);
+ } else if (atomic_read(&this_afe.status) != 0) {
+ pr_err("%s: config cmd failed\n", __func__);
+ ret = -EINVAL;
+ }
+ pr_debug("%s: leave %d\n", __func__, ret);
+ return ret;
+}
+
+int afe_port_set_mad_type(u16 port_id, enum afe_mad_type mad_type)
+{
+ int i;
+
+ i = port_id - SLIMBUS_0_RX;
+ if (i < 0 || i > ARRAY_SIZE(afe_ports_mad_type)) {
+ pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
+ return -EINVAL;
+ }
+ atomic_set(&afe_ports_mad_type[i], mad_type);
+ return 0;
+}
+
+enum afe_mad_type afe_port_get_mad_type(u16 port_id)
+{
+ int i;
+
+ i = port_id - SLIMBUS_0_RX;
+ if (i < 0 || i > ARRAY_SIZE(afe_ports_mad_type)) {
+ pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
+ return MAD_HW_NONE;
+ }
+ return (enum afe_mad_type) atomic_read(&afe_ports_mad_type[i]);
+}
+
+int afe_set_config(enum afe_config_type config_type, void *config_data, int arg)
+{
+ int ret;
+
+ pr_debug("%s: enter config_type %d\n", __func__, config_type);
+ ret = afe_q6_interface_prepare();
+ if (ret) {
+ pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ switch (config_type) {
+ case AFE_SLIMBUS_SLAVE_CONFIG:
+ ret = afe_send_slimbus_slave_cfg(config_data);
+ if (!ret)
+ ret = afe_init_cdc_reg_config();
+ else
+ pr_err("%s: Sending slimbus slave config failed %d\n",
+ __func__, ret);
+ break;
+ case AFE_CDC_REGISTERS_CONFIG:
+ ret = afe_send_codec_reg_config(config_data);
+ break;
+ case AFE_SLIMBUS_SLAVE_PORT_CONFIG:
+ ret = afe_send_slimbus_slave_port_cfg(config_data, arg);
+ break;
+ default:
+ pr_err("%s: unknown configuration type", __func__);
+ ret = -EINVAL;
+ }
+
+ pr_debug("%s: leave ret %d\n", __func__, ret);
+ return ret;
+}
+
+static int afe_send_cmd_port_start(u16 port_id)
+{
+ struct afe_port_cmd_device_start start;
+ int ret, index;
+
+ pr_debug("%s: enter\n", __func__);
+ index = q6audio_get_port_index(port_id);
+ if (q6audio_validate_port(port_id) < 0) {
+ pr_err("%s: port id: %#x\n", __func__, port_id);
+ return -EINVAL;
+ }
+
+ start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ start.hdr.pkt_size = sizeof(start);
+ start.hdr.src_port = 0;
+ start.hdr.dest_port = 0;
+ start.hdr.token = index;
+ start.hdr.opcode = AFE_PORT_CMD_DEVICE_START;
+ start.port_id = q6audio_get_port_id(port_id);
+ pr_debug("%s: cmd device start opcode[0x%x] port id[0x%x]\n",
+ __func__, start.hdr.opcode, start.port_id);
+
+ ret = afe_apr_send_pkt(&start, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE enable for port %#x failed %d\n", __func__,
+ port_id, ret);
+ } else if (this_afe.task != current) {
+ this_afe.task = current;
+ pr_debug("task_name = %s pid = %d\n",
+ this_afe.task->comm, this_afe.task->pid);
+ }
+
+ pr_debug("%s: leave %d\n", __func__, ret);
+ return ret;
+}
+
int afe_port_start(u16 port_id, union afe_port_config *afe_config,
u32 rate) /* This function is no blocking */
{
- struct afe_port_cmd_device_start start;
struct afe_audioif_config_command config;
- int ret;
+ int ret = 0;
int cfg_type;
int index = 0;
+ enum afe_mad_type mad_type;
if (!afe_config) {
pr_err("%s: Error, no configuration data\n", __func__);
@@ -529,6 +860,7 @@
port_id = VIRTUAL_ID_TO_PORTID(port_id);
pr_debug("%s: port id: %#x\n", __func__, port_id);
+
index = q6audio_get_port_index(port_id);
if (q6audio_validate_port(port_id) < 0) {
pr_err("%s: port id: %#x\n", __func__, port_id);
@@ -539,11 +871,19 @@
if (IS_ERR_VALUE(ret))
return ret;
- if (q6audio_validate_port(port_id) < 0) {
- pr_err("%s: Failed : Invalid Port id = %#x\n", __func__,
- port_id);
- ret = -EINVAL;
- goto fail_cmd;
+ afe_send_cal(port_id);
+
+ /* Start SW MAD module */
+ mad_type = afe_port_get_mad_type(port_id);
+ pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
+ mad_type);
+ if (mad_type != MAD_HW_NONE) {
+ ret = afe_turn_onoff_hw_mad(mad_type, true);
+ if (ret) {
+ pr_err("%s: afe_turn_onoff_hw_mad failed %d\n",
+ __func__, ret);
+ return ret;
+ }
}
config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -593,6 +933,7 @@
case SLIMBUS_3_TX:
case SLIMBUS_4_RX:
case SLIMBUS_4_TX:
+ case SLIMBUS_5_TX:
cfg_type = AFE_PARAM_ID_SLIMBUS_CONFIG;
break;
case RT_PROXY_PORT_001_RX:
@@ -623,69 +964,17 @@
config.port = *afe_config;
- atomic_set(&this_afe.state, 1);
- atomic_set(&this_afe.status, 0);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
- if (ret < 0) {
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
pr_err("%s: AFE enable for port %#x failed\n", __func__,
port_id);
- ret = -EINVAL;
goto fail_cmd;
- }
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
-
- if (!ret) {
- pr_err("%s: wait_event timeout IF CONFIG\n", __func__);
- ret = -EINVAL;
- goto fail_cmd;
- }
- if (atomic_read(&this_afe.status) != 0) {
+ } else if (atomic_read(&this_afe.status) != 0) {
pr_err("%s: config cmd failed\n", __func__);
ret = -EINVAL;
goto fail_cmd;
}
- /* send AFE cal */
- afe_send_cal(port_id);
-
- start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
- start.hdr.pkt_size = sizeof(start);
- start.hdr.src_port = 0;
- start.hdr.dest_port = 0;
- start.hdr.token = index;
- start.hdr.opcode = AFE_PORT_CMD_DEVICE_START;
- start.port_id = q6audio_get_port_id(port_id);
- pr_debug("%s: cmd device start opcode[0x%x] port id[0x%x]\n",
- __func__, start.hdr.opcode, start.port_id);
-
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
-
- if (IS_ERR_VALUE(ret)) {
- pr_err("%s: AFE enable for port %#x failed\n", __func__,
- port_id);
- ret = -EINVAL;
- goto fail_cmd;
- }
-
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
-
- if (!ret) {
- pr_err("%s: wait_event timeout PORT START\n", __func__);
- ret = -EINVAL;
- goto fail_cmd;
- }
- if (this_afe.task != current)
- this_afe.task = current;
-
- pr_debug("task_name = %s pid = %d\n",
- this_afe.task->comm, this_afe.task->pid);
-
- return 0;
+ return afe_send_cmd_port_start(port_id);
fail_cmd:
return ret;
@@ -725,6 +1014,7 @@
case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX;
case SLIMBUS_4_RX: return IDX_SLIMBUS_4_RX;
case SLIMBUS_4_TX: return IDX_SLIMBUS_4_TX;
+ case SLIMBUS_5_TX: return IDX_SLIMBUS_5_TX;
case AFE_PORT_ID_PRIMARY_MI2S_RX:
return IDX_AFE_PORT_ID_PRIMARY_MI2S_RX;
case AFE_PORT_ID_QUATERNARY_MI2S_RX:
@@ -837,25 +1127,13 @@
__func__, config.param.payload_size, config.pdata.param_size,
sizeof(config), sizeof(config.param), sizeof(config.port),
sizeof(struct apr_hdr), config.pdata.param_id);
- atomic_set(&this_afe.state, 1);
- atomic_set(&this_afe.status, 0);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
- if (ret < 0) {
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
pr_err("%s: AFE enable for port %d opcode[0x%x]failed\n",
__func__, port_id, cfg_type);
- ret = -EINVAL;
goto fail_cmd;
- }
-
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- ret = -EINVAL;
- goto fail_cmd;
- }
- if (atomic_read(&this_afe.status) != 0) {
+ } else if (atomic_read(&this_afe.status) != 0) {
pr_err("%s: config cmd failed\n", __func__);
ret = -EINVAL;
goto fail_cmd;
@@ -870,24 +1148,14 @@
start.port_id = q6audio_get_port_id(port_id);
pr_debug("%s: cmd device start opcode[0x%x] port id[0x%x]\n",
__func__, start.hdr.opcode, start.port_id);
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
- if (ret < 0) {
+
+ ret = afe_apr_send_pkt(&start, &this_afe.wait[index]);
+ if (ret) {
pr_err("%s: AFE enable for port %d failed\n", __func__,
port_id);
- ret = -EINVAL;
- goto fail_cmd;
- }
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- ret = -EINVAL;
goto fail_cmd;
}
- return 0;
fail_cmd:
return ret;
}
@@ -934,23 +1202,10 @@
lb_cmd.routing_mode = LB_MODE_DEFAULT;
lb_cmd.enable = (enable ? 1 : 0);
lb_cmd.loopback_cfg_minor_version = AFE_API_VERSION_LOOPBACK_CONFIG;
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lb_cmd);
- if (ret < 0) {
- pr_err("%s: AFE loopback failed\n", __func__);
- ret = -EINVAL;
- goto done;
- }
- pr_debug("%s: waiting for this_afe.wait[%d]\n", __func__, index);
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- ret = -EINVAL;
- }
-done:
+ ret = afe_apr_send_pkt(&lb_cmd, &this_afe.wait[index]);
+ if (ret)
+ pr_err("%s: AFE loopback failed %d\n", __func__, ret);
return ret;
}
@@ -1016,24 +1271,13 @@
set_param.rx_port_id = port_id;
set_param.gain = volume;
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &set_param);
- if (ret < 0) {
+ ret = afe_apr_send_pkt(&set_param, &this_afe.wait[index]);
+ if (ret) {
pr_err("%s: AFE param set failed for port %d\n",
__func__, port_id);
- ret = -EINVAL;
goto fail_cmd;
}
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (ret < 0) {
- pr_err("%s: wait_event timeout\n", __func__);
- ret = -EINVAL;
- goto fail_cmd;
- }
- return 0;
fail_cmd:
return ret;
}
@@ -1060,9 +1304,8 @@
start.port_id = port_id;
start.timing = 1;
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
- if (ret < 0) {
+ ret = afe_apr_send_pkt(&start, NULL);
+ if (ret) {
pr_err("%s: AFE enable for port %d failed %d\n",
__func__, port_id, ret);
return -EINVAL;
@@ -1095,25 +1338,13 @@
start.hdr.opcode = AFE_PSEUDOPORT_CMD_START;
start.port_id = port_id;
start.timing = 1;
-
start.hdr.token = index;
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
- if (ret < 0) {
+
+ ret = afe_apr_send_pkt(&start, &this_afe.wait[index]);
+ if (ret)
pr_err("%s: AFE enable for port %d failed %d\n",
__func__, port_id, ret);
- return -EINVAL;
- }
-
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- return -EINVAL;
- }
-
- return 0;
+ return ret;
}
int afe_pseudo_port_stop_nowait(u16 port_id)
@@ -1141,17 +1372,13 @@
stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
stop.port_id = port_id;
stop.reserved = 0;
-
stop.hdr.token = index;
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
- if (ret < 0) {
+
+ ret = afe_apr_send_pkt(&stop, NULL);
+ if (ret)
pr_err("%s: AFE close failed %d\n", __func__, ret);
- return -EINVAL;
- }
- return 0;
-
+ return ret;
}
int afe_stop_pseudo_port(u16 port_id)
@@ -1180,24 +1407,13 @@
stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
stop.port_id = port_id;
stop.reserved = 0;
-
stop.hdr.token = index;
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
- if (ret < 0) {
+
+ ret = afe_apr_send_pkt(&stop, &this_afe.wait[index]);
+ if (ret)
pr_err("%s: AFE close failed %d\n", __func__, ret);
- return -EINVAL;
- }
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- return -EINVAL;
- }
-
- return 0;
+ return ret;
}
uint32_t afe_req_mmap_handle(struct afe_audio_client *ac)
@@ -1480,15 +1696,11 @@
mregion_pl->shm_addr_msw = 0x00;
mregion_pl->mem_size_bytes = dma_buf_sz;
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) mmap_region_cmd);
- if (ret < 0) {
+ ret = afe_apr_send_pkt(mmap_region_cmd, NULL);
+ if (ret)
pr_err("%s: AFE memory map cmd failed %d\n",
__func__, ret);
- ret = -EINVAL;
- return ret;
- }
- return 0;
+ return ret;
}
int q6afe_audio_client_buf_free_contiguous(unsigned int dir,
struct afe_audio_client *ac)
@@ -1576,24 +1788,11 @@
/* Todo */
index = mregion.hdr.token = IDX_RSVD_2;
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
- if (ret < 0) {
+ ret = afe_apr_send_pkt(&mregion, &this_afe.wait[index]);
+ if (ret)
pr_err("%s: AFE memory unmap cmd failed %d\n",
__func__, ret);
- ret = -EINVAL;
- return ret;
- }
-
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- ret = -EINVAL;
- return ret;
- }
- return 0;
+ return ret;
}
int afe_cmd_memory_unmap_nowait(u32 mem_map_handle)
@@ -1623,13 +1822,11 @@
mregion.hdr.opcode = AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS;
mregion.mem_map_handle = mem_map_handle;
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
- if (ret < 0) {
+ ret = afe_apr_send_pkt(&mregion, NULL);
+ if (ret)
pr_err("%s: AFE memory unmap cmd failed %d\n",
__func__, ret);
- ret = -EINVAL;
- }
- return 0;
+ return ret;
}
int afe_register_get_events(u16 port_id,
@@ -1675,14 +1872,11 @@
rtproxy.port_id = port_id;
rtproxy.reserved = 0;
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &rtproxy);
- if (ret < 0) {
+ ret = afe_apr_send_pkt(&rtproxy, NULL);
+ if (ret)
pr_err("%s: AFE reg. rtproxy_event failed %d\n",
__func__, ret);
- ret = -EINVAL;
- return ret;
- }
- return 0;
+ return ret;
}
int afe_unregister_get_events(u16 port_id)
@@ -1734,24 +1928,11 @@
this_afe.rx_private_data = NULL;
}
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &rtproxy);
- if (ret < 0) {
+ ret = afe_apr_send_pkt(&rtproxy, &this_afe.wait[index]);
+ if (ret)
pr_err("%s: AFE enable Unreg. rtproxy_event failed %d\n",
__func__, ret);
- ret = -EINVAL;
- return ret;
- }
-
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- ret = -EINVAL;
- return ret;
- }
- return 0;
+ return ret;
}
int afe_rt_proxy_port_write(u32 buf_addr_p, u32 mem_map_handle, int bytes)
@@ -1781,14 +1962,11 @@
afecmd_wr.available_bytes = bytes;
afecmd_wr.reserved = 0;
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &afecmd_wr);
- if (ret < 0) {
+ ret = afe_apr_send_pkt(&afecmd_wr, NULL);
+ if (ret)
pr_err("%s: AFE rtproxy write to port 0x%x failed %d\n",
__func__, afecmd_wr.port_id, ret);
- ret = -EINVAL;
- return ret;
- }
- return 0;
+ return ret;
}
@@ -1818,14 +1996,11 @@
afecmd_rd.available_bytes = bytes;
afecmd_rd.mem_map_handle = mem_map_handle;
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &afecmd_rd);
- if (ret < 0) {
+ ret = afe_apr_send_pkt(&afecmd_rd, NULL);
+ if (ret)
pr_err("%s: AFE rtproxy read cmd to port 0x%x failed %d\n",
__func__, afecmd_rd.port_id, ret);
- ret = -EINVAL;
- return ret;
- }
- return 0;
+ return ret;
}
#ifdef CONFIG_DEBUG_FS
@@ -2102,25 +2277,10 @@
cmd_sidetone.routing_mode = LB_MODE_SIDETONE;
cmd_sidetone.enable = enable;
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &cmd_sidetone);
- if (ret < 0) {
+ ret = afe_apr_send_pkt(&cmd_sidetone, &this_afe.wait[index]);
+ if (ret)
pr_err("%s: AFE sidetone failed for tx_port:%d rx_port:%d\n",
__func__, tx_port_id, rx_port_id);
- ret = -EINVAL;
- goto fail_cmd;
- }
-
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (ret < 0) {
- pr_err("%s: wait_event timeout\n", __func__);
- ret = -EINVAL;
- goto fail_cmd;
- }
- return 0;
-fail_cmd:
return ret;
}
@@ -2217,12 +2377,9 @@
stop.port_id = port_id;
stop.reserved = 0;
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
-
- if (IS_ERR_VALUE(ret)) {
+ ret = afe_apr_send_pkt(&stop, NULL);
+ if (ret)
pr_err("%s: AFE close failed\n", __func__);
- ret = -EINVAL;
- }
fail_cmd:
return ret;
@@ -2232,10 +2389,10 @@
int afe_close(int port_id)
{
struct afe_port_cmd_device_stop stop;
+ enum afe_mad_type mad_type;
int ret = 0;
int index = 0;
-
if (this_afe.apr == NULL) {
pr_err("AFE is already closed\n");
ret = -EINVAL;
@@ -2245,9 +2402,25 @@
port_id = q6audio_convert_virtual_to_portid(port_id);
index = q6audio_get_port_index(port_id);
- if (q6audio_validate_port(port_id) < 0)
+ if (q6audio_validate_port(port_id) < 0) {
+ pr_warn("%s: Not a valid port id 0x0%x\n", __func__, port_id);
return -EINVAL;
+ }
+ mad_type = afe_port_get_mad_type(port_id);
+ pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
+ mad_type);
+ if (mad_type != MAD_HW_NONE) {
+ pr_debug("%s: Turn off MAD\n", __func__);
+ ret = afe_turn_onoff_hw_mad(mad_type, false);
+ if (ret) {
+ pr_err("%s: afe_turn_onoff_hw_mad failed %d\n",
+ __func__, ret);
+ return ret;
+ }
+ } else {
+ pr_debug("%s: Not a MAD port\n", __func__);
+ }
stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
@@ -2259,23 +2432,10 @@
stop.port_id = q6audio_get_port_id(port_id);
stop.reserved = 0;
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
+ ret = afe_apr_send_pkt(&stop, &this_afe.wait[index]);
+ if (ret)
+ pr_err("%s: AFE close failed %d\n", __func__, ret);
- if (ret < 0) {
- pr_err("%s: AFE close failed\n", __func__);
- ret = -EINVAL;
- goto fail_cmd;
- }
-
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- ret = -EINVAL;
- goto fail_cmd;
- }
fail_cmd:
return ret;
}
diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c
index 4ed0fb7..d3d335d 100644
--- a/sound/soc/msm/qdsp6v2/q6audio-v2.c
+++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c
@@ -44,6 +44,7 @@
case SLIMBUS_2_RX: return IDX_SLIMBUS_2_RX;
case SLIMBUS_2_TX: return IDX_SLIMBUS_2_TX;
case SLIMBUS_4_TX: return IDX_SLIMBUS_4_TX;
+ case SLIMBUS_5_TX: return IDX_SLIMBUS_5_TX;
case INT_BT_SCO_RX: return IDX_INT_BT_SCO_RX;
case INT_BT_SCO_TX: return IDX_INT_BT_SCO_TX;
case INT_BT_A2DP_RX: return IDX_INT_BT_A2DP_RX;
@@ -91,6 +92,7 @@
case SLIMBUS_2_RX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_RX;
case SLIMBUS_2_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_TX;
case SLIMBUS_4_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX;
+ case SLIMBUS_5_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX;
case INT_BT_SCO_RX: return AFE_PORT_ID_INTERNAL_BT_SCO_RX;
case INT_BT_SCO_TX: return AFE_PORT_ID_INTERNAL_BT_SCO_TX;
case INT_BT_A2DP_RX: return AFE_PORT_ID_INTERNAL_BT_A2DP_RX;
@@ -109,7 +111,9 @@
case AFE_PORT_ID_SECONDARY_MI2S_TX:
return AFE_PORT_ID_SECONDARY_MI2S_TX;
- default: return -EINVAL;
+ default:
+ pr_warn("%s: Invalid port_id %d\n", __func__, port_id);
+ return -EINVAL;
}
}
int q6audio_convert_virtual_to_portid(u16 port_id)
@@ -185,6 +189,7 @@
case SLIMBUS_2_RX:
case SLIMBUS_2_TX:
case SLIMBUS_4_TX:
+ case SLIMBUS_5_TX:
case INT_BT_SCO_RX:
case INT_BT_SCO_TX:
case INT_BT_A2DP_RX:
diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c
new file mode 100644
index 0000000..f2b531a
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/q6lsm.c
@@ -0,0 +1,813 @@
+/*
+ * Copyright (c) 2013, Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/memory_alloc.h>
+#include <linux/debugfs.h>
+#include <linux/time.h>
+#include <linux/atomic.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/lsm_params.h>
+#include <sound/q6lsm.h>
+#include <asm/ioctls.h>
+#include <mach/memory.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_subsystem_map.h>
+#include "audio_acdb.h"
+
+#define APR_TIMEOUT (5 * HZ)
+#define LSM_CAL_SIZE 4096
+
+enum {
+ CMD_STATE_CLEARED = 0,
+ CMD_STATE_WAIT_RESP = 1,
+};
+
+enum {
+ LSM_INVALID_SESSION_ID = 0,
+ LSM_MIN_SESSION_ID = 1,
+ LSM_MAX_SESSION_ID = 8,
+};
+
+struct lsm_common {
+ void *apr;
+ atomic_t apr_users;
+ uint32_t lsm_cal_addr;
+ uint32_t lsm_cal_size;
+ uint32_t mmap_handle_for_cal;
+ struct mutex apr_lock;
+};
+
+static struct lsm_common lsm_common;
+
+/*
+ * mmap_handle_p can point either client->sound_model.mem_map_handle or
+ * lsm_common.mmap_handle_for_cal.
+ * mmap_lock must be held while accessing this.
+ */
+static spinlock_t mmap_lock;
+static uint32_t *mmap_handle_p;
+
+static spinlock_t lsm_session_lock;
+static struct lsm_client *lsm_session[LSM_MAX_SESSION_ID + 1];
+
+static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv);
+static int q6lsm_send_cal(struct lsm_client *client);
+static int q6lsm_snd_model_buf_free(struct lsm_client *client);
+
+static int q6lsm_callback(struct apr_client_data *data, void *priv)
+{
+ struct lsm_client *client = (struct lsm_client *)priv;
+ uint32_t token;
+ uint32_t *payload;
+
+ if (!client || !data) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ payload = data->payload;
+ pr_debug("%s: Session %d opcode 0x%x token 0x%x payload size %d\n",
+ __func__, client->session,
+ data->opcode, data->token, data->payload_size);
+
+ if (data->opcode == APR_BASIC_RSP_RESULT) {
+ token = data->token;
+ switch (payload[0]) {
+ case LSM_SESSION_CMD_START:
+ case LSM_SESSION_CMD_STOP:
+ case LSM_SESSION_CMD_SET_PARAMS:
+ case LSM_SESSION_CMD_OPEN_TX:
+ case LSM_SESSION_CMD_CLOSE_TX:
+ case LSM_SESSION_CMD_REGISTER_SOUND_MODEL:
+ case LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL:
+ case LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS:
+ if (token != client->session &&
+ payload[0] !=
+ LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL) {
+ pr_err("%s: Invalid session %d receivced expected %d\n",
+ __func__, token, client->session);
+ return -EINVAL;
+ }
+ if (atomic_cmpxchg(&client->cmd_state,
+ CMD_STATE_WAIT_RESP,
+ CMD_STATE_CLEARED) ==
+ CMD_STATE_WAIT_RESP)
+ wake_up(&client->cmd_wait);
+ break;
+ default:
+ pr_debug("%s: Unknown command 0x%x\n",
+ __func__, payload[0]);
+ break;
+ }
+ return 0;
+ }
+
+ if (client->cb)
+ client->cb(data->opcode, data->token, data->payload,
+ client->priv);
+
+ return 0;
+}
+
+static int q6lsm_session_alloc(struct lsm_client *client)
+{
+ unsigned long flags;
+ int n, ret = -ENOMEM;
+
+ spin_lock_irqsave(&lsm_session_lock, flags);
+ for (n = LSM_MIN_SESSION_ID; n <= LSM_MAX_SESSION_ID; n++) {
+ if (!lsm_session[n]) {
+ lsm_session[n] = client;
+ ret = n;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&lsm_session_lock, flags);
+ return ret;
+}
+
+static void q6lsm_session_free(struct lsm_client *client)
+{
+ unsigned long flags;
+
+ pr_debug("%s: Freeing session ID %d\n", __func__, client->session);
+ spin_lock_irqsave(&lsm_session_lock, flags);
+ lsm_session[client->session] = LSM_INVALID_SESSION_ID;
+ spin_unlock_irqrestore(&lsm_session_lock, flags);
+ client->session = LSM_INVALID_SESSION_ID;
+}
+
+static void *q6lsm_mmap_apr_reg(void)
+{
+ if (atomic_inc_return(&lsm_common.apr_users) == 1) {
+ lsm_common.apr =
+ apr_register("ADSP", "LSM", q6lsm_mmapcallback,
+ 0x0FFFFFFFF, &lsm_common);
+ if (!lsm_common.apr) {
+ pr_debug("%s Unable to register APR LSM common port\n",
+ __func__);
+ atomic_dec(&lsm_common.apr_users);
+ }
+ }
+
+ return lsm_common.apr;
+}
+
+static int q6lsm_mmap_apr_dereg(void)
+{
+ if (atomic_read(&lsm_common.apr_users) <= 0) {
+ WARN("%s: APR common port already closed\n", __func__);
+ } else {
+ if (atomic_dec_return(&lsm_common.apr_users) == 0) {
+ apr_deregister(lsm_common.apr);
+ pr_debug("%s:APR De-Register common port\n", __func__);
+ }
+ }
+ return 0;
+}
+
+struct lsm_client *q6lsm_client_alloc(app_cb cb, void *priv)
+{
+ struct lsm_client *client;
+ int n;
+
+ pr_debug("%s: enter\n", __func__);
+ client = kzalloc(sizeof(struct lsm_client), GFP_KERNEL);
+ if (!client)
+ return NULL;
+ n = q6lsm_session_alloc(client);
+ if (n <= 0) {
+ kfree(client);
+ return NULL;
+ }
+
+ pr_debug("%s: New client session %d\n", __func__, client->session);
+ client->session = n;
+ client->cb = cb;
+ client->priv = priv;
+ client->apr = apr_register("ADSP", "LSM", q6lsm_callback,
+ ((client->session) << 8 | 0x0001), client);
+
+ if (client->apr == NULL) {
+ pr_err("%s: Registration with APR failed\n", __func__);
+ goto fail;
+ }
+
+ pr_debug("%s Registering the common port with APR\n", __func__);
+ client->mmap_apr = q6lsm_mmap_apr_reg();
+ if (!client->mmap_apr) {
+ pr_err("%s: APR registration failed\n", __func__);
+ goto fail;
+ }
+
+ init_waitqueue_head(&client->cmd_wait);
+ mutex_init(&client->cmd_lock);
+ atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
+ pr_debug("%s: New client allocated\n", __func__);
+ return client;
+fail:
+ q6lsm_client_free(client);
+ return NULL;
+}
+
+void q6lsm_client_free(struct lsm_client *client)
+{
+ if (!client || !client->session)
+ return;
+
+ apr_deregister(client->apr);
+ client->mmap_apr = NULL;
+ q6lsm_session_free(client);
+ q6lsm_mmap_apr_dereg();
+ mutex_destroy(&client->cmd_lock);
+ kfree(client);
+}
+
+/*
+ * q6lsm_apr_send_pkt : If wait == true, hold mutex to prevent from preempting
+ * other thread's wait.
+ * If mmap_handle_p != NULL, disable irq and spin lock to
+ * protect mmap_handle_p
+ */
+static int q6lsm_apr_send_pkt(struct lsm_client *client, void *handle,
+ void *data, bool wait, uint32_t *mmap_p)
+{
+ int ret;
+ unsigned long flags = 0;
+
+ pr_debug("%s: enter wait %d\n", __func__, wait);
+ if (wait)
+ mutex_lock(&lsm_common.apr_lock);
+ if (mmap_p) {
+ WARN_ON(!wait);
+ spin_lock_irqsave(&mmap_lock, flags);
+ mmap_handle_p = mmap_p;
+ }
+ atomic_set(&client->cmd_state, CMD_STATE_WAIT_RESP);
+ ret = apr_send_pkt(client->apr, data);
+ if (mmap_p)
+ spin_unlock_irqrestore(&mmap_lock, flags);
+
+ if (ret < 0) {
+ pr_err("%s: apr_send_pkt failed %d\n", __func__, ret);
+ } else if (wait) {
+ ret = wait_event_timeout(client->cmd_wait,
+ (atomic_read(&client->cmd_state) ==
+ CMD_STATE_CLEARED),
+ APR_TIMEOUT);
+ if (likely(ret))
+ ret = 0;
+ else
+ pr_err("%s: wait timedout\n", __func__);
+ } else {
+ ret = 0;
+ }
+ if (wait)
+ mutex_unlock(&lsm_common.apr_lock);
+
+ pr_debug("%s: leave ret %d\n", __func__, ret);
+ return ret;
+}
+
+static void q6lsm_add_hdr(struct lsm_client *client, struct apr_hdr *hdr,
+ uint32_t pkt_size, bool cmd_flg)
+{
+ pr_debug("%s: pkt_size %d cmd_flg %d session %d\n", __func__,
+ pkt_size, cmd_flg, client->session);
+ hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(sizeof(struct apr_hdr)),
+ APR_PKT_VER);
+ hdr->src_svc = APR_SVC_LSM;
+ hdr->src_domain = APR_DOMAIN_APPS;
+ hdr->dest_svc = APR_SVC_LSM;
+ hdr->dest_domain = APR_DOMAIN_ADSP;
+ hdr->src_port = ((client->session << 8) & 0xFF00) | 0x01;
+ hdr->dest_port = ((client->session << 8) & 0xFF00) | 0x01;
+ hdr->pkt_size = pkt_size;
+ if (cmd_flg)
+ hdr->token = client->session;
+}
+
+int q6lsm_open(struct lsm_client *client)
+{
+ int rc;
+ struct lsm_stream_cmd_open_tx open;
+
+ memset(&open, 0, sizeof(open));
+ q6lsm_add_hdr(client, &open.hdr, sizeof(open), true);
+
+ open.hdr.opcode = LSM_SESSION_CMD_OPEN_TX;
+ open.app_id = 1;
+ open.sampling_rate = 16000;
+
+ rc = q6lsm_apr_send_pkt(client, client->apr, &open, true, NULL);
+ if (rc)
+ pr_err("%s: Open failed opcode 0x%x, rc %d\n",
+ __func__, open.hdr.opcode, rc);
+
+ pr_debug("%s: leave %d\n", __func__, rc);
+ return rc;
+}
+
+static int q6lsm_set_params(struct lsm_client *client)
+{
+ int rc;
+ struct lsm_cmd_set_params params;
+ struct lsm_params_payload *payload = ¶ms.payload;
+
+ pr_debug("%s: enter\n", __func__);
+ q6lsm_add_hdr(client, ¶ms.hdr, sizeof(params), true);
+
+ params.hdr.opcode = LSM_SESSION_CMD_SET_PARAMS;
+ params.data_payload_addr_lsw = 0;
+ params.data_payload_addr_msw = 0;
+ params.mem_map_handle = 0;
+ params.data_payload_size = sizeof(struct lsm_params_payload);
+
+ payload->op_mode.common.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
+ payload->op_mode.common.param_id = LSM_PARAM_ID_OPERATION_MODE;
+ payload->op_mode.common.param_size =
+ sizeof(struct lsm_param_op_mode) - sizeof(payload->op_mode.common);
+ payload->op_mode.common.reserved = 0;
+ payload->op_mode.minor_version = 1;
+ payload->op_mode.mode = client->mode;
+ payload->op_mode.reserved = 0;
+
+ payload->connect_to_port.common.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
+ payload->connect_to_port.common.param_id = LSM_PARAM_ID_CONNECT_TO_PORT;
+ payload->connect_to_port.common.param_size =
+ sizeof(payload->connect_to_port) - sizeof(payload->op_mode.common);
+ payload->connect_to_port.common.reserved = 0;
+ payload->connect_to_port.minor_version = 1;
+ payload->connect_to_port.port_id = client->connect_to_port;
+ payload->connect_to_port.reserved = 0;
+
+ payload->kwds.common.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
+ payload->kwds.common.param_id = LSM_PARAM_ID_KEYWORD_DETECT_SENSITIVITY;
+ payload->kwds.common.param_size =
+ sizeof(payload->kwds) - sizeof(payload->op_mode.common);
+ payload->kwds.common.reserved = 0;
+ payload->kwds.minor_version = 1;
+ payload->kwds.keyword_sensitivity = client->kw_sensitivity;
+ payload->kwds.reserved = 0;
+
+ payload->uds.common.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
+ payload->uds.common.param_id = LSM_PARAM_ID_USER_DETECT_SENSITIVITY;
+ payload->uds.common.param_size =
+ sizeof(payload->uds) - sizeof(payload->op_mode.common);
+ payload->uds.common.reserved = 0;
+ payload->uds.minor_version = 1;
+ payload->uds.user_sensitivity = client->user_sensitivity;
+ payload->uds.reserved = 0;
+
+ rc = q6lsm_apr_send_pkt(client, client->apr, ¶ms, true, NULL);
+ if (rc)
+ pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
+ __func__, params.hdr.opcode, rc);
+
+ pr_debug("%s: leave %d\n", __func__, rc);
+ return rc;
+}
+
+int q6lsm_register_sound_model(struct lsm_client *client,
+ enum lsm_detection_mode mode, u16 minkeyword,
+ u16 minuser, bool detectfailure)
+{
+ int rc;
+ struct lsm_cmd_reg_snd_model cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ if (mode == LSM_MODE_KEYWORD_ONLY_DETECTION) {
+ client->mode = 0x01;
+ } else if (mode == LSM_MODE_USER_KEYWORD_DETECTION) {
+ client->mode = 0x03;
+ } else {
+ pr_err("%s: Incorrect detection mode %d\n", __func__, mode);
+ return -EINVAL;
+ }
+ client->mode |= detectfailure << 2;
+ client->kw_sensitivity = minkeyword;
+ client->user_sensitivity = minuser;
+ client->connect_to_port = AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX;
+
+ rc = q6lsm_set_params(client);
+ if (rc < 0) {
+ pr_err("%s: Failed to set lsm config params\n", __func__);
+ return rc;
+ }
+ rc = q6lsm_send_cal(client);
+ if (rc < 0) {
+ pr_err("%s: Failed to send calibration data\n", __func__);
+ return rc;
+ }
+
+ q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd), true);
+ cmd.hdr.opcode = LSM_SESSION_CMD_REGISTER_SOUND_MODEL;
+ cmd.model_addr_lsw = client->sound_model.phys;
+ cmd.model_addr_msw = 0;
+ cmd.model_size = client->sound_model.size;
+ /* read updated mem_map_handle by q6lsm_mmapcallback */
+ rmb();
+ cmd.mem_map_handle = client->sound_model.mem_map_handle;
+
+ pr_debug("%s: lsw %x, size %d, handle %x\n", __func__,
+ cmd.model_addr_lsw, cmd.model_size, cmd.mem_map_handle);
+ rc = q6lsm_apr_send_pkt(client, client->apr, &cmd, true, NULL);
+ if (rc)
+ pr_err("%s: Failed cmd op[0x%x]rc[%d]\n", __func__,
+ cmd.hdr.opcode, rc);
+ else
+ pr_debug("%s: Register sound model succeeded\n", __func__);
+
+ return rc;
+}
+
+int q6lsm_deregister_sound_model(struct lsm_client *client)
+{
+ int rc;
+ struct lsm_cmd_reg_snd_model cmd;
+
+ if (!client || !client->apr) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+ pr_debug("%s: session[%d]", __func__, client->session);
+
+ memset(&cmd, 0, sizeof(cmd));
+ q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd.hdr), false);
+ cmd.hdr.opcode = LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL;
+
+ rc = q6lsm_apr_send_pkt(client, client->apr, &cmd.hdr, true, NULL);
+ if (rc < 0) {
+ pr_err("%s: Failed cmd opcode 0x%x, rc %d\n", __func__,
+ cmd.hdr.opcode, rc);
+ } else {
+ pr_debug("%s: Deregister sound model succeeded\n", __func__);
+ q6lsm_snd_model_buf_free(client);
+ }
+
+ return rc;
+}
+
+static void q6lsm_add_mmaphdr(struct lsm_client *client, struct apr_hdr *hdr,
+ u32 pkt_size, u32 cmd_flg, u32 token)
+{
+ pr_debug("%s:pkt size=%d cmd_flg=%d session=%d\n", __func__, pkt_size,
+ cmd_flg, client->session);
+ hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ hdr->src_port = 0x00;
+ hdr->dest_port = client->session;
+ if (cmd_flg)
+ hdr->token = token;
+ hdr->pkt_size = pkt_size;
+ return;
+}
+
+static int q6lsm_memory_map_regions(struct lsm_client *client,
+ uint32_t dma_addr_p, uint32_t dma_buf_sz,
+ uint32_t *mmap_p)
+{
+ struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
+ struct avs_shared_map_region_payload *mregions = NULL;
+ void *mmap_region_cmd = NULL;
+ void *payload = NULL;
+ int rc;
+ int cmd_size = 0;
+
+ pr_debug("%s: dma_addr_p 0x%x, dma_buf_sz %d, session %d\n",
+ __func__, dma_addr_p, dma_buf_sz, client->session);
+
+ cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions) +
+ sizeof(struct avs_shared_map_region_payload);
+
+ mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+ if (!mmap_region_cmd)
+ return -ENOMEM;
+
+ mmap_regions = (struct avs_cmd_shared_mem_map_regions *)mmap_region_cmd;
+ q6lsm_add_mmaphdr(client, &mmap_regions->hdr, cmd_size, true,
+ (client->session << 8));
+
+ mmap_regions->hdr.opcode = LSM_SESSION_CMD_SHARED_MEM_MAP_REGIONS;
+ mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
+ mmap_regions->num_regions = 1;
+ mmap_regions->property_flag = 0x00;
+ payload = ((u8 *)mmap_region_cmd +
+ sizeof(struct avs_cmd_shared_mem_map_regions));
+ mregions = (struct avs_shared_map_region_payload *)payload;
+
+ mregions->shm_addr_lsw = dma_addr_p;
+ mregions->shm_addr_msw = 0;
+ mregions->mem_size_bytes = dma_buf_sz;
+
+ rc = q6lsm_apr_send_pkt(client, client->mmap_apr, mmap_region_cmd,
+ true, mmap_p);
+ if (rc)
+ pr_err("%s: Failed mmap_regions opcode 0x%x, rc %d\n",
+ __func__, mmap_regions->hdr.opcode, rc);
+
+ pr_debug("%s: leave %d\n", __func__, rc);
+ kfree(mmap_region_cmd);
+ return rc;
+}
+
+static int q6lsm_send_cal(struct lsm_client *client)
+{
+ int rc;
+
+ struct lsm_cmd_set_params params;
+ struct acdb_cal_block lsm_cal;
+
+ pr_debug("%s: enter\n", __func__);
+
+ memset(&lsm_cal, 0, sizeof(lsm_cal));
+ get_lsm_cal(&lsm_cal);
+ if (!lsm_cal.cal_size) {
+ pr_err("%s: Could not get LSM calibration data\n", __func__);
+ rc = -EINVAL;
+ goto bail;
+ }
+
+ /* Cache mmap address, only map once or if new addr */
+ if ((lsm_common.lsm_cal_addr != lsm_cal.cal_paddr) ||
+ (lsm_cal.cal_size > lsm_common.lsm_cal_size)) {
+ if (lsm_common.lsm_cal_addr != 0)
+ afe_cmd_memory_unmap(lsm_cal.cal_paddr);
+
+ rc = q6lsm_memory_map_regions(client, lsm_cal.cal_paddr,
+ LSM_CAL_SIZE,
+ &lsm_common.mmap_handle_for_cal);
+ if (rc < 0) {
+ pr_err("%s: Calibration data memory map failed\n",
+ __func__);
+ goto bail;
+ }
+ lsm_common.lsm_cal_addr = lsm_cal.cal_paddr;
+ lsm_common.lsm_cal_size = LSM_CAL_SIZE;
+ }
+
+ q6lsm_add_hdr(client, ¶ms.hdr, sizeof(params), true);
+ params.hdr.opcode = LSM_SESSION_CMD_SET_PARAMS;
+ params.data_payload_addr_lsw = lsm_cal.cal_paddr;
+ params.data_payload_addr_msw = 0;
+ /* read updated mem_map_handle by q6lsm_mmapcallback */
+ rmb();
+ params.mem_map_handle = lsm_common.mmap_handle_for_cal;
+ params.data_payload_size = lsm_cal.cal_size;
+
+ rc = q6lsm_apr_send_pkt(client, client->apr, ¶ms, true, NULL);
+ if (rc)
+ pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
+ __func__, params.hdr.opcode, rc);
+bail:
+ return rc;
+}
+
+static int q6lsm_memory_unmap_regions(struct lsm_client *client)
+{
+ struct avs_cmd_shared_mem_unmap_regions unmap;
+ int rc = 0;
+ int cmd_size = 0;
+
+ cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
+ q6lsm_add_mmaphdr(client, &unmap.hdr, cmd_size,
+ true, (client->session << 8));
+ unmap.hdr.opcode = LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS;
+ unmap.mem_map_handle = client->sound_model.mem_map_handle;
+
+ pr_debug("%s: unmap handle 0x%x\n", __func__, unmap.mem_map_handle);
+ rc = q6lsm_apr_send_pkt(client, client->mmap_apr, &unmap, true,
+ NULL);
+ if (rc)
+ pr_err("%s: Failed mmap_regions opcode 0x%x rc %d\n",
+ __func__, unmap.hdr.opcode, rc);
+
+ return rc;
+}
+
+static int q6lsm_snd_model_buf_free(struct lsm_client *client)
+{
+ int rc;
+
+ pr_debug("%s: Session id %d\n", __func__, client->session);
+ mutex_lock(&client->cmd_lock);
+ rc = q6lsm_memory_unmap_regions(client);
+ if (rc < 0) {
+ pr_err("%s CMD Memory_unmap_regions failed\n", __func__);
+ } else if (client->sound_model.data) {
+ ion_unmap_kernel(client->sound_model.client,
+ client->sound_model.handle);
+ ion_free(client->sound_model.client,
+ client->sound_model.handle);
+ ion_client_destroy(client->sound_model.client);
+ client->sound_model.data = NULL;
+ client->sound_model.phys = 0;
+ }
+ mutex_unlock(&client->cmd_lock);
+ return rc;
+}
+
+static struct lsm_client *q6lsm_get_lsm_client(int session_id)
+{
+ unsigned long flags;
+ struct lsm_client *client = NULL;
+
+ spin_lock_irqsave(&lsm_session_lock, flags);
+ if (session_id < LSM_MIN_SESSION_ID || session_id > LSM_MAX_SESSION_ID)
+ pr_err("%s: Invalid session %d\n", __func__, session_id);
+ else if (!lsm_session[session_id])
+ pr_err("%s: Not an active session %d\n", __func__, session_id);
+ else
+ client = lsm_session[session_id];
+ spin_unlock_irqrestore(&lsm_session_lock, flags);
+
+ return client;
+}
+
+/*
+ * q6lsm_mmapcallback : atomic context
+ */
+static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv)
+{
+ unsigned long flags;
+ uint32_t sid = 0;
+ const uint32_t *payload = data->payload;
+ const uint32_t command = payload[0];
+ const uint32_t retcode = payload[1];
+ struct lsm_client *client = NULL;
+
+ pr_debug("%s: opcode 0x%x command 0x%x return code 0x%x\n", __func__,
+ data->opcode, command, retcode);
+
+ sid = (data->token >> 8) & 0x0F;
+ client = q6lsm_get_lsm_client(sid);
+ if (!client) {
+ pr_debug("%s: Session %d already freed\n", __func__, sid);
+ return 0;
+ }
+
+ switch (data->opcode) {
+ case LSM_SESSION_CMDRSP_SHARED_MEM_MAP_REGIONS:
+ if (atomic_read(&client->cmd_state) == CMD_STATE_WAIT_RESP) {
+ spin_lock_irqsave(&mmap_lock, flags);
+ *mmap_handle_p = command;
+ /* spin_unlock_irqrestore implies barrier */
+ spin_unlock_irqrestore(&mmap_lock, flags);
+ atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
+ wake_up(&client->cmd_wait);
+ }
+ break;
+ case APR_BASIC_RSP_RESULT:
+ if (command == LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS) {
+ atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
+ wake_up(&client->cmd_wait);
+ } else {
+ pr_warn("%s: Unexpected command 0x%x\n", __func__,
+ command);
+ }
+ break;
+ default:
+ pr_debug("%s: command 0x%x return code 0x%x\n",
+ __func__, command, retcode);
+ break;
+ }
+ if (client->cb)
+ client->cb(data->opcode, data->token,
+ data->payload, client->priv);
+ return 0;
+}
+
+int q6lsm_snd_model_buf_alloc(struct lsm_client *client, uint32_t len)
+{
+ int rc = -EINVAL;
+
+ if (!client)
+ goto fail;
+
+ mutex_lock(&client->cmd_lock);
+ if (!client->sound_model.data) {
+ client->sound_model.client =
+ msm_ion_client_create(UINT_MAX, "lsm_client");
+ if (IS_ERR_OR_NULL(client->sound_model.client)) {
+ pr_err("%s: ION create client for AUDIO failed\n",
+ __func__);
+ goto fail;
+ }
+ client->sound_model.handle =
+ ion_alloc(client->sound_model.client,
+ len, SZ_4K, (0x1 << ION_AUDIO_HEAP_ID), 0);
+ if (IS_ERR_OR_NULL(client->sound_model.handle)) {
+ pr_err("%s: ION memory allocation for AUDIO failed\n",
+ __func__);
+ goto fail;
+ }
+
+ rc = ion_phys(client->sound_model.client,
+ client->sound_model.handle,
+ (ion_phys_addr_t *)&client->sound_model.phys,
+ (size_t *)&len);
+ if (rc) {
+ pr_err("%s: ION get physical mem failed, rc%d\n",
+ __func__, rc);
+ goto fail;
+ }
+
+ client->sound_model.data =
+ ion_map_kernel(client->sound_model.client,
+ client->sound_model.handle);
+ if (IS_ERR_OR_NULL(client->sound_model.data)) {
+ pr_err("%s: ION memory mapping failed\n", __func__);
+ goto fail;
+ }
+ memset(client->sound_model.data, 0, len);
+ client->sound_model.size = len;
+ } else {
+ rc = -EBUSY;
+ goto fail;
+ }
+ mutex_unlock(&client->cmd_lock);
+
+ rc = q6lsm_memory_map_regions(client, client->sound_model.phys,
+ client->sound_model.size,
+ &client->sound_model.mem_map_handle);
+ if (rc < 0) {
+ pr_err("%s:CMD Memory_map_regions failed\n", __func__);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ q6lsm_snd_model_buf_free(client);
+ return rc;
+}
+
+static int q6lsm_cmd(struct lsm_client *client, int opcode, bool wait)
+{
+ struct apr_hdr hdr;
+ int rc;
+
+ pr_debug("%s: enter opcode %d wait %d\n", __func__, opcode, wait);
+ q6lsm_add_hdr(client, &hdr, sizeof(hdr), true);
+ switch (opcode) {
+ case LSM_SESSION_CMD_START:
+ case LSM_SESSION_CMD_STOP:
+ case LSM_SESSION_CMD_CLOSE_TX:
+ hdr.opcode = opcode;
+ break;
+ default:
+ pr_err("%s: Invalid opcode %d\n", __func__, opcode);
+ return -EINVAL;
+ }
+ rc = q6lsm_apr_send_pkt(client, client->apr, &hdr, wait, NULL);
+ if (rc)
+ pr_err("%s: Failed commmand 0x%x\n", __func__, hdr.opcode);
+
+ pr_debug("%s: leave %d\n", __func__, rc);
+ return rc;
+}
+
+int q6lsm_start(struct lsm_client *client, bool wait)
+{
+ return q6lsm_cmd(client, LSM_SESSION_CMD_START, wait);
+}
+
+int q6lsm_stop(struct lsm_client *client, bool wait)
+{
+ return q6lsm_cmd(client, LSM_SESSION_CMD_STOP, wait);
+}
+
+int q6lsm_close(struct lsm_client *client)
+{
+ return q6lsm_cmd(client, LSM_SESSION_CMD_CLOSE_TX, true);
+}
+
+static int __init q6lsm_init(void)
+{
+ pr_debug("%s\n", __func__);
+ spin_lock_init(&lsm_session_lock);
+ spin_lock_init(&mmap_lock);
+ mutex_init(&lsm_common.apr_lock);
+ return 0;
+}
+
+device_initcall(q6lsm_init);